# AiSD lista 2 - Wojciech Adamiec ## Zadania Deklarowane: 2, 4, 5, 6 ### Zadanie 2. :::info ![alt text](https://i.imgur.com/mIJrT9p.png) ::: ```= def policz(I[1...n]): S = {} koniec = -INF I.sortuj(dla par <p, k> -> k.rosnąco) Dla każdego <p, k> w I: Jeśli (p >= koniec): S.dodaj(<p, k>) koniec = k Zwróć S ``` Nasz algorytm zwraca zbiór $S$. Załóżmy, że $S'$ jest zbiorem optymalnym zbierającym najkrótsze odcinki. Rozpatrujemy pierwszą różnice patrząc od lewej strony. Nasz algorytm wybrał odcinek $s$. Optymalny algorytm wybrał $s'$. Istnieją trzy przypadki: 1. $s.koniec > s'.koniec$ (Niemożliwe, idziemy po posortowanej tablicy) 2. $s.koniec < s'.koniec$ ![](https://i.imgur.com/69We0C6.png) Przypadek nie może zajść, bo wówczas $S'$ nie spełniałby założeń: Mógłby wziąć odcinek $A$ zamiast $B$, a potem kontynuować bez zmian. 4. $s.koniec = s'.koniec$ (dostaniemy rozwiązanie inne, ale również optymalne) **Złożoność czasowa**: $O(n \log n)$ **Złożoność pamięciowa**: $O(n)$ ### Zadanie 4. ![](https://i.imgur.com/phIJsS7.png) Wprowadźmy pojęcie warstwy drzewa $t$: Warstwa $0$ - wszystkie liście drzewa $t$ Warstwa $1$ - wszystkie liście drzewa $t$ po obcięciu od $t$ wierzchołków z warstwy 0 Warstwa $n$ - wszystkie liście drzewa $t$ po obcięciu od $t$ z warstw $0, 1, ..., n-1$ Załóżmy na chwilę, że $k$ jest parzyste. Będziemy chcieli pokolorować $\frac{k}{2}$ warstw zaczynając od warstwy $0$. W ten sposób dowolna ścieżka prosta w grafie będzie zawierać nie więcej niż $k$ pokolorowanych wierzchołków. Dlaczego tak jest? Każda ścieżka prosta może wejść w obszar pomalowanych wierzchołków w co najwyżej 2 miejscach (przez obszar rozumiemy pomalowane warstwy) - na początku ścieżki i jej końcu. W każdym takim obszarze jest co najwyżej $\frac{k}{2}$ pomalowanych wierzchołków. Poniżej przykład dla $k=4$. ![](https://i.imgur.com/o7fpIBZ.png) Kla $k$ nieparzystego będziemy chcieli pokolorować $\lfloor \frac{k}{2} \rfloor$ warstw. Następnie będziemy chcieli pokolorować jeszcze jeden dodatkowy wierzchołek. Łatwo zauważyć, że to może być dowolny wierzchołek - wtedy ścieżka z największa ilością pomalowanych wierzchołków może ich mieć co najwyżej $\lfloor \frac{k}{2} \rfloor + \lfloor \frac{k}{2} \rfloor + 1 = k$ Jednocześnie zauważamy, że jeśli pomalowalibyśmy więcej niż 1 dodatkowy wierzchołek -- wówczas można by wskazać ścieżkę, która zawierałaby $k + 1$ pomalowanych wierzchołków (przechodziłaby przez oba pomalowane wierzchołki oraz wchodziła początkiem i końcem w pomalowane warstwy), co burzy nam założenia zadania. **Algorytm**: Załóżmy, że mamy drzewo w postaci listy sąsiedztwa. ```= Niech N(v) będzie oznaczać wszystkich sąsiadów v L, R - puste listy Dla każdego v: Jeśli |N(v)| = 1 L.dodaj(v) Zrób k/2 razy: Dla każdego wierzchołka v z L: pokoloruj v Dla ojca p wierzchołka v (czyli jedyny wierzchołek z N(v)): N(p).usuń(v) Jeśli |N(p)| = 1 R.dodaj(p) L = R R = [] Jeśli k mod 2 == 1: Pomaluj dowolny niepomalowany wierzchołek (jeśli istnieje) ``` **Złożoność czasowa**: $O(n)$ # Każdy wierzchołek pokolorujemy co najwyżej raz **Złożoność pamięciowa**: $O(n + m)$ # Graf i dwie listy ### Zadanie 5. ![](https://i.imgur.com/9EJxbxt.png) Zacznijmy od wprowadzenia, że każda krawędź jest unikalna. Jeśli nie to łatwo to zagwarantować. (jakaś wartość unikalna po przecinku związana z id). Algorytm: ![](https://i.imgur.com/r7Dun9G.png) Zauważmy, że skoro krawędzie są unikalne to jeśli jakiś wierzchołek $A$ (superwierzchołek) wybierze krawędź prowadzącą do $B$ to wówczas $B$ wybierze tą samą krawędź. Spojrzymy na ten algorytm nieco inaczej - dla nas pojedynczym krokiem będzie wybranie jednej krawędzi. Będziemy chcieli przeprowadzić indukcję względem iteracji. Niezmiennikiem pętli będzie dla nas to, że mamy do czynienia z lasem drzew MST. W każdym kroku (w każdym realnym kroku, to znaczy pomijając te, które wybierają krawędź już wybraną) w naszym lesie będzie o jedno drzewo mniej. **Dowód:** Weźmy dowolny graf $n$ wierzchołkowy o unikalnych krawędziach. **Baza:** Mamy las $n$ drzew (wierzchołków). Każde z nich jest poprawnym drzewem MST. **Krok:** Założmy, że po $n$ iteracjach dalej mamy do czynienia z lasem drzew MST (drzew jest teraz $n$ mniej). W tym kroku algorytm weźmie jakieś 2 drzewa MST i znajdzie najmniejszą krawędź między nimi. Od teraz algorytm będzie traktował te dwa drzewa i tą krawędź jako nowe drzewo. Widzimy, że ilość drzew w lesie zmalała o 1. Pokażemy, że połączone ze sobą w ten sposób drzewa MST dalej tworzą drzewo MST. Skorzystamy tutaj z **cut property**: ![](https://i.imgur.com/lJejzEj.png) Własność ta mówi, że dla każdego cięcia, jeśli krawędź $e$ jest najmniejszą krawędzią tego cięcia to wówczas musi należeć do MST. W naszym przypadku krawędzie są unikalne, a co za tym idzie istnieje tylko jedno drzewo MST. Zauważmy, że jeśli potrakujemy wierzchołki z podrzew, które chcemy połączyć jako zbiór wierzchołków grafu, to wówczas cięciem są wszystke krawędzie które łączą jedno drzewo z drugim. Nasz algorytm wybiera najmniejszą z nich, a zatem właśnie tą, która na mocy **cut property** musi znaleźć się w naszym MST. Zatem istotnie po tym kroku będziemy mieli nadal do czynienia z lasem drzew MST pomniejszonym o 1 drzewo. W ostatniej iteracji połączymy ze sobą ostatnie dwa drzewa MST i na mocy tego samego lematu wiemy, że powstałe w ten sposób drzewo również jest MST - tym razem jest to drzewo rozpięte na całym naszym grafie. Zmniejszająca się ilość drzew w lesie gwarantuje nam, że algorytm się zakończy. ### Zadanie 6. ![](https://i.imgur.com/nqIn7ZW.png) Zacznijmy od krótkich lematów: **Lemat 1:** Dla dowolnego cyklu $C$ i krawędzi $e \in C$ w grafie, jeśli waga $e$ jest większa, niż waga wszystkich innych krawędzi w cyklu $C$, to $e$ nie należy do żadnego minimalnego drzewa spinajacego w grafie. **Dowód:** Załóżmy nie wprost, że $e \in MST$. Usunięcie $e$ spowoduje rozspójnienie $MST$ na dwa poddrzewa $T_1$ i $T_2$. Skoro $e \in C$ to istnieje jakaś krawędź $e'$, taka, że $e'\in C$ i końce $e'$ leżą odpowiednio w $T_1$ i $T_2$. Z założenia wiemy, że $e$ jest krawędzią o największej wadze w $C$, zatem $e'$ ma mniejszą wagę niż $e$. Możemy wówczas połączyć drzewa $T_1$ i $T_2$ krawędzią $e'$. Dostaniemy dzięki temu nowe drzewo rozpinające o wadze mniejszej niż $MST$. Doszliśmy zatem do sprzeczności. **Lemat 2:** Jeśli w każdym cyklu $C$ takim, że $e \in C$ istnieje krawędź cięższa od $e$ to wówczas istnieje takie $MST$, że $e \in MST$. **Dowód:** Załóżmy nie wprost, że $e$ nie należy do żadnego minimalnego drzewa rozpinającego. Weźmy dowolne takie drzewo i nazwijmy je $M$. Wówczas $M \cup \{e\}$ zawiera cykl. Jednocześnie wiemy, że w tym cyklu jest jakaś inna cięższa od $e$ krawędź. Możemy wyrzucić tą krawędź otrzymując MST o mniejszej wadze niż $M$ co powoduje sprzeczność. **Algorytm:** Niech krawędź $e$ łączy wierzchołki $v$ i $u$. Usuńmy krawędź $e$ z grafu $G$ tworząc graf $G'$. Za pomocą algorytmu DFS, w którym będziemy rozważać tylko krawędzie o mniejszej wadze niż waga $e$ sprawdźmy czy istnieje połączenie między $v$ i $u$. Jeśli takie połączenie istnieje wówczas wiemy, że w grafie $G$ znajdował się cykl $C$, a krawędź $e \in C$ była najcięższą krawędzią tego cyklu. Z lematu wiemy wówczas, że krawędź $e$ nie należy do żadnego drzewa rozpinającego grafu $G$. Jeśli takie połączenie nie istnieje wówczas są dwie możliwości: 1. Cykl nie istnieje. Wówczas $e$ musi należeć do MST. 2. W każdym cyklu, w którym jest $e$ istnieje krawędź cięższa od $e$. Z lematu 2 wiemy, że $e$ należy do jakiegoś MST. **Złożoność czasowa**: $O(n + m)$ # DFS **Złożoność pamięciowa**: $O(n + m)$ # Graf