diff --git a/09-grafy/abstraktni-matice.py b/09-grafy/abstraktni-matice.py new file mode 100755 index 0000000000000000000000000000000000000000..1dfa32d0035a03939f2a14f6fb3c82033c11b818 --- /dev/null +++ b/09-grafy/abstraktni-matice.py @@ -0,0 +1,84 @@ +#!/usr/bin/python3 +# Abstraktní reprezentace grafu třídou, +# implementace třídy pomocí matice sousednosti + +from collections import deque + +class Graf: + """Reprezentace grafu maticí sousednosti.""" + + def __init__(self, n): + self.n = n + self.matice = [[0]*n for _ in range(n)] + + def __repr__(self): + return str(self.matice) + + def pridej_hranu(self, i, j): + self.matice[i][j] = 1 + + # Na cyklus přes všechny vrcholy tentokrát potřebujeme vyrobit + # iterátor. Pozor, nestačí definovat metodu __iter__, protože + # potřebujeme předat jako parametr vrchol, jehož sousedy chceme + # vyjmenovat. + def sousede(self, i): + return SousedeIt(self, i) + +class SousedeIt: + """Iterátor přes sousedy zadaného vrcholu.""" + + def __init__(self, graf, i): + # Iterátor si pamatuje: + self.graf = graf # ke kterému grafu patří + self.i = i # sousedy kterého vrcholu vyjmenovává + self.j = 0 # aktuální polohu + + # Pozor: Pokud napíšeme "for v in graf.sousede(u)", cyklus for bude chtít + # po objektu vráceném z metody sousede, aby vyrobil svůj iterátor. Jenže + # v našem případě to už iterátor je, tak ho musíme naučit, aby vrátil sám + # sebe. To je v Pythonu standardní postup: když iterátoru řeknete, že má + # vyrobit iterátor, vrátí sebe sama. + def __iter__(self): + return self + + # Vrátí dalšího souseda v pořadí + def __next__(self): + # Kde je další jednička v řádku? + while self.j < self.graf.n and self.graf.matice[self.i][self.j] == 0: + self.j += 1 + if self.j < self.graf.n: + self.j += 1 + return self.j - 1 + else: + raise StopIteration + + +# Původní příklad na prohledávání do šířky jsme přepsali tak, +# aby s grafem pracoval výhradně pomocí třídy Graf. + +n = int(input()) +graf = Graf(n) +for i in range(n): + for j in input().split(): + graf.pridej_hranu(i, int(j)) + +print(graf) + +def prohledej(v0): + byl_jsem = [False] * n + byl_jsem[v0] = True + vzdalenost = [None] * n + vzdalenost[v0] = 0 + fronta = deque() + fronta.append(v0) + + while fronta: + u = fronta.popleft() + print(u, vzdalenost[u]) + for v in graf.sousede(u): + if not byl_jsem[v]: + byl_jsem[v] = True + vzdalenost[v] = vzdalenost[u] + 1 + fronta.append(v) + +prohledej(3) diff --git a/09-grafy/abstraktni-seznamy.py b/09-grafy/abstraktni-seznamy.py new file mode 100755 index 0000000000000000000000000000000000000000..b0f5ca720aba92944bb25a6267607c4ba746ea9d --- /dev/null +++ b/09-grafy/abstraktni-seznamy.py @@ -0,0 +1,53 @@ +#!/usr/bin/python3 +# Abstraktní reprezentace grafu třídou, +# implementace třídy pomocí seznamů sousedů. + +from collections import deque + +class Graf: + """Reprezentace grafu seznamy sousedů.""" + + def __init__(self, n): + self.n = n + self.seznam_sousedu = [[] for _ in range(n)] + + def __repr__(self): + return str(self.seznam_sousedu) + + def pridej_hranu(self, i, j): + self.seznam_sousedu[i].append(j) + + # Používáme jako "for v in graf.sousede(u)" + def sousede(self, i): + return self.seznam_sousedu[i] + + +# Původní příklad na prohledávání do šířky jsme přepsali tak, +# aby s grafem pracoval výhradně pomocí třídy Graf. + +n = int(input()) +graf = Graf(n) +for i in range(n): + for j in input().split(): + graf.pridej_hranu(i, int(j)) + +print(graf) + +def prohledej(v0): + byl_jsem = [False] * n + byl_jsem[v0] = True + vzdalenost = [None] * n + vzdalenost[v0] = 0 + fronta = deque() + fronta.append(v0) + + while fronta: + u = fronta.popleft() + print(u, vzdalenost[u]) + for v in graf.sousede(u): + if not byl_jsem[v]: + byl_jsem[v] = True + vzdalenost[v] = vzdalenost[u] + 1 + fronta.append(v) + +prohledej(3) diff --git a/09-grafy/do-sirky-matice.py b/09-grafy/do-sirky-matice.py new file mode 100755 index 0000000000000000000000000000000000000000..af3b3675fd5cdd23f3f792bcb98c07ce3980a0ad --- /dev/null +++ b/09-grafy/do-sirky-matice.py @@ -0,0 +1,37 @@ +#!/usr/bin/python3 +# Prohledávání grafu do šířky +# Graf je reprezentovaný pomocí matice sousednosti + +from pprint import pprint +from collections import deque + +# Načteme vstup: nejprve počet vrcholů, pak n řádků se sousedy jednotlivých vrcholů +n = int(input()) +matice = [[0]*n for _ in range(n)] +for i in range(n): + for j in input().split(): + j = int(j) + matice[i][j] = 1 + +# Pro kontrolu vypíšeme reprezentaci grafu (pprint = pretty print) +pprint(matice) + +# Prohledávání do šířky +def prohledej(v0): + byl_jsem = [False] * n + byl_jsem[v0] = True + vzdalenost = [None] * n + vzdalenost[v0] = 0 + fronta = deque() + fronta.append(v0) + + while fronta: + u = fronta.popleft() + print(u, vzdalenost[u]) + for v in range(n): + if matice[u][v] == 1 and not byl_jsem[v]: + byl_jsem[v] = True + vzdalenost[v] = vzdalenost[u] + 1 + fronta.append(v) + +prohledej(3) diff --git a/09-grafy/do-sirky-seznamy.py b/09-grafy/do-sirky-seznamy.py new file mode 100755 index 0000000000000000000000000000000000000000..526a4cf1c88d46605eb0616707b6850c3409b564 --- /dev/null +++ b/09-grafy/do-sirky-seznamy.py @@ -0,0 +1,34 @@ +#!/usr/bin/python3 +# Prohledávání grafu do šířky +# Graf je reprezentovaný pomocí seznamů sousedů + +from collections import deque + +# Načteme vstup: nejprve počet vrcholů, pak n řádků se sousedy jednotlivých vrcholů +n = int(input()) +sousede = [] +for i in range(n): + sousede.append([ int(j) for j in input().split() ]) + +# Pro kontrolu vypíšeme reprezentaci grafu +print(sousede) + +# Prohledávání do šířky +def prohledej(v0): + byl_jsem = [False] * n + byl_jsem[v0] = True + vzdalenost = [None] * n + vzdalenost[v0] = 0 + fronta = deque() + fronta.append(v0) + + while fronta: + u = fronta.popleft() + print(u, vzdalenost[u]) + for v in sousede[u]: + if not byl_jsem[v]: + byl_jsem[v] = True + vzdalenost[v] = vzdalenost[u] + 1 + fronta.append(v) + +prohledej(3) diff --git a/09-grafy/iterator.py b/09-grafy/iterator.py new file mode 100755 index 0000000000000000000000000000000000000000..3694179d3d981e6e7d88c60f8c18e53f6a8636c2 --- /dev/null +++ b/09-grafy/iterator.py @@ -0,0 +1,40 @@ +#!/usr/bin/python3 +# Příklad na iterátory: vlastní implementace range(n) + +class MyRange: + + def __init__(self, n): + self.n = n + + # Touto magickou metodou objektu řekneme, aby vyrobil iterátor + def __iter__(self): + return MyIter(self) + +class MyIter: + + # Iterátoru při inicializaci říkáme, ke kterému MyRange patří + def __init__(self, rng): + # Iterátor si pamatuje range a poslední vygenerované číslo + self.rng = rng + self.i = -1 + + # Touto magickou metodou po iterátoru chceme, aby vydal další prvek, + # nebo vyvolal výjimku StopIteration, pokud už žádný další neexistuje. + def __next__(self): + self.i += 1 + if self.i < self.rng.n: + return self.i + else: + raise StopIteration + +for x in MyRange(10): + print(x) + +# Uvnitř for-u se stane toto: +# +# r = MyRange(10) +# it = r.__iter__() <- řekneme objektu MyRange, aby vyrobil iterátor +# while True: +# x = it.__next__() <- řekneme iterátoru, aby vydal další prvek +# pokud nastala výjimka StopIteration, skonči +# print(x) <- tělo cyklu diff --git a/09-grafy/test.in b/09-grafy/test.in new file mode 100644 index 0000000000000000000000000000000000000000..d3f40aa8691135f8081860aac82dd1496c181b30 --- /dev/null +++ b/09-grafy/test.in @@ -0,0 +1,6 @@ +5 +1 +2 +3 +1 4 +