#!/usr/bin/python3 #vim: foldmethod=marker fileencoding=utf-8 import sys, collections # Vstup # 1. řádek: počet vrcholů a hran # další řádky: jednotlivé orientované hrany (dvojice čísel vrcholů indexovaných od nuly) # čísla na řádku vždy oddělena mezerou# # # Příklad ze zadání (s čárkovanou hranou, na posledním řádku, vrchol C je číslo 0): # 5 7 # 0 1 # 1 2 # 2 0 # 0 3 # 3 4 # 4 0 # 4 3 N, M = map(int, input().strip().split()) N *= 2 # každý vrchol rozdvojíme # mapování číslo vrcholu -> seznam sousedů # položky seznamu sousedů jsou dvojice (číslo hrany, číslo sousedního vrcholu) sousede = [] for i in range(N): sousede.append([]) e = 0 for i in range(M): u,v = map(int, input().strip().split()) # Vytvoříme nová čísla vrcholů: pro vrchol $w$ bude mít dárcovský podvrchol # číslo 2w a příjemcovský 2w+1 u = 2*u v = 2*v + 1 sousede[u].append((e,v)) sousede[v].append((e,u)) e += 1 parovani = [False] * M ## HOPCROFT-KARP {{{ def vrchol_volny(u): # one-liner verze pro drsné pythonisty: # return all( hr(u,v) not in parovani for v in sousede[u] ) for e, v in sousede[u]: if parovani[e]: return False return True def bfs(): global vrstvy vrstvy = [-1] * N fronta = collections.deque() # spojový seznam # Prohledáváme ze všech sudých (dárcovských) vrcholů for u in range(0, N, 2): if vrchol_volny(u): vrstvy[u] = 0 fronta.append(u) while fronta: u = fronta.popleft() vrstva = vrstvy[u] for hrana, soused in sousede[u]: if vrstvy[soused] == -1: vrstvy[soused] = vrstva + 1 fronta.append(soused) if vrchol_volny(soused): # Vrať číslo poslední vrstvy (=délku nejkratší zlepšující cesty) return vrstva + 1 return -1 # Nenalazena zlepšující cesta -> máme maximální párování def dfs(u, vrstva=0): global znacky, vrstvy, posledni_vrstva if znacky[u]: return False znacky[u] = True if vrchol_volny(u) and vrstva != 0: return True for hrana, soused in sousede[u]: if vrstvy[soused] != -1: vrstva_souseda = vrstvy[soused] elif vrstva == posledni_vrstva - 1: vrstva_souseda = posledni_vrstva if vrstva_souseda == vrstva + 1: if dfs(soused, vrstva + 1): # Vracíme se po nalezené zlepšující cestě a invertujeme stav hran. parovani[hrana] = not parovani[hrana] return True return False def faze(): global vrstvy, posledni_vrstva posledni_vrstva = bfs() if posledni_vrstva == -1: return False global znacky znacky = [False] * N for u in range(0, N, 2): # prohledáváme z sudých (dárcovských) vrcholů if vrchol_volny(u): dfs(u) return True ### KONEC: Hopcroft-Karp }}} while True: # Zlepšuj párování, dokud to jde if not faze(): break velikost = 0 for e in range(M): if parovani[e]: velikost += 1 # pro odvážné: velikost = sum(parovani) # (rozmyslete si, proč funguje ;-)) print("Velikost párování: ", velikost) if (velikost == N//2): # Nalezené párování je perfektní print("Ano") else: print("Ne")