Aproximační Algoritmy
- Základní definice
- Metrický TSP
- Quicksort
- Konflikty v distribuovaných systémech
- Globální minimální řez
- Rozvrhování
- Hledání disjunktních cest
- Splnitelnost (MAX-SAT)
- Pokrývací problémy
- Hashovací funkce
- Testování
- Perfektní párování
- Odkazy
Úvodní informace
Tato stránka obsahuje moje poznámky z přednášky Jiřího Sgalla z akademického roku 2021/2022 (MFF UK). Pokud by byla někde chyba/nejasnost, nebo byste rádi něco přidali, tak stránku můžete upravit pull requestem (případně mi dejte vědět na mail).
Základní definice
Definice (Optimalizační problém) je
- množina všech vstupů/instancí
- množina všech ohodnocených grafů
- množina přípustných řešení
- pro daný ohodnocený graf všechny kostry
- účelová funkce
- součet hran na kostře
- bit (zda chceme maximalizovat nebo minimalizovat)
- maximalizujeme
Definice (NP-Optimalizační problém) je , pro které platí stejné věci jako pro normální optimalizační problémy, ale navíc
- délka přípustných řešení .
- jazyk dvojic je v (rychle umíme ověřit, zda je řešení přípustné)
- počitatelná v polynomiálním čase
Pro minimalizační zajišťujeme, že naše je vždy dostatečně malé.
Pro maximalizační zajišťujeme, že je vždy dostatečně velké.
Definice: algoritmus je -aproximační alg., pokud:
- v polynomiálním čase v na vstupu najde
- pro minimalizační problém:
- pro maximalizační problém:
Pravděpodobnost v algoritmech
- algoritmy s chybou: někdy dělají chybu, ale většinou ji neudělají
- bez chyb, běží v průměrném čase polynomiálním
- třída : jazyky, pro které existuje polynomiální algoritmus , který ověří správnost:
- třída : jazyky, pro které existuje polynomiální algoritmus , který ověří správnost:
Metrický TSP
- Vstup: metrika na úplném ohodnoceném grafu
- metrika vrcholy splňují následující:
- trojúhelníkova nerovnost
- symetrie
- pokud by to nebyla metrika, tak poly algoritmus neexistuje (jde převést na normální TSP)
- metrika vrcholy splňují následující:
- Výstup: cyklus na všech vrcholech
- Cíl: minimalizovat
Kostrový algoritmus
Algoritmus (kostrový):
- najdeme minimální kostru
- navštívíme všechny vrcholy (například přes DFS), čímž dostaneme tah přes všechny vrcholy
- zkrátíme ji na cyklus tak, že vynecháme opakující-se vrcholy
Věta: algoritmus je -aproximační.
Důkaz: kostra je nejvýše tak velká, jako optimální řešení a tenhle algoritmus je lepší než kostry (díky trojúhelníkové nerovnosti a symetrii – procházíme i tam i zpět)
Christofidesův algoritmus
(👀): brát hrany dvakrát je plýtvání – pospojujeme liché vrcholy přes minimální párování, abychom nemuseli chodit tam a zpět
- najdeme minimální kostru
- najdeme minimální perfektní párování na vrcholech s lichými stupni v
- vždy existuje, jelikož máme úplný graf a vrcholů s lichým stupňem je sudý počet
- zkrátíme na cyklus
- děláme je tak, že vybereme dvě hrany incidentní s vrcholem a nahradíme je za jednu
Věta: algoritmus je -aproximační.
Důkaz:
Důkaz uděláme obrázkem:
Alespoň jeden z párování v cylku bude , jelikož celý cyklus je lepší optimální řešení.
Poznámka:
- v realitě se algoritmus chová výrazně lépe, například až k faktoru
- dnes umíme -aproximaci
- TSP v rovině: existuje -aproximační schéma (ale stále je těžký)
Quicksort
Algoritmus (quicksort):
- konec, vystoupíme (base case)
- jinak vybereme uniformě náhodně
-
- posloupnost má všechny prvky rozdílné, takže chceme ostrá nerovnítka
- rekurzivně se zavoláme na
- vystoupíme
Věta: quicksort má průměrnou časovou složitost .
Pro připomenutí:
- (indikátorová veličina)
Důkaz: počítáme
- zavedeme indikátorové veličiny
Lemma: nechť . Pak
Důkaz: to, že se dva prvky porovnají musí znamentat, že jeden z jich byl pivot, ale žádný mezi nimi pivot nebyl (jelikož by je to rozdělilo). Musíme tedy vybrat právě jeden z těchto dvou z intervalu , kde je celkově čísel.
Sečtením přes všechny dvojice dostaváme následující:
Konflikty v distribuovaných systémech
- procesorů se snaží o přístup k jednomu zdroji
- přímá komunikace není možná
- v každém cylku může každý procesor požadovat přístup
- povede se pouze, když o něho žádá jeden
Algoritmus:
- v každém cylku zkus s pravděpodobností přistoupit ke zdroji
- si nastavíme tak, aby to vyšlo hezky
- opakuj, dokud se ti to nepovede
Věta: algoritmus s s pravděpodobností alespoň uspěje po cyklech.
Důkaz: modifikujme algoritmus, aby zkoušel přistupovat i po té, co ho získal (lehčí počítání, které pouze zhorší pravděpodobnost úspěchu).
Nechť je jev, že -tý proces upěl v -tém cyklu. Pak
Nyní počítáme které říká, že -tý proces neuspěje v žádném z cyklů:
To, že neexistuje proces, který neuspěje, odhadneme jako
Globální minimální řez
- Vstup: neorientovaný graf
- Výstup: řez
- Cíl: minimalizovat
Přímočarý algoritmus
Algoritmus:
- převedeme graf na ohodnocený s jednotkovými cenami
- zafixujeme vrchol
- pro všechny ostatní vrcholy najdeme minimalní řez
- vrátíme minimum
- umíme vyřešit řádové v
Spojující algoritmus
Algoritmus:
- vybereme náhodnou hranu a její vrcholy spojíme do jednoho
- opakujeme, dokud nemáme pouze dva vrcholy
- zbylé hrany na konci jsou náš řez
- idea je to, že hran v minimálním řezu je málo a nejspíš se do nich netrefíme
- pracujeme s multigrafy – při kontrakci zachováváme hrany
- umíme ho implementovat rychle (řádově )
- opravdu produkuje řez, protože vrcholy mezi výslednými komponentami danými vrcholy nemizí
(👀): multigraf s vrcholy a min. řezem velikosti má alespoň hran.
- každý vrchol sám o sobě tvoří řez, pak stačí přes všechny posčítat…
Věta: pravděpodobnost, že najdeme daný minimální řez je alespoň .
Důkaz: nechť jev, že v prvních iteracích jsme nevybrali hranu z .
- (žádnou jsme ještě nevybrali)
- , z čehož vyplývá:
Důsledek: každý graf má globálních minimálních řezů.
- jeden takový je například cyklus – ten má opravdu řádově tolik řezů
Důkaz: každý běh algoritmu vystoupí právě jeden řez. Kdyby jich bylo více, tak nám pravděpodobnost nevychází (jevy jsou disjunktní).
(👀): Pro opakování algoritmu výše dostáváme nejmenší řez s pravděpodobností
Poznámka: algoritmus můžeme vylepšit tak, že části, ve kterých se nejvíce dělají chyby (konkrétně ty pozdější) opakujeme vícekrát (a vezmeme minimum).
Rozvrhování
- Vstup: strojů, úloh, každá o délce
- Výstup: rozklad (rozvržení úloh na stroje)
- Cíl: minimalizovat (délka nejdelšího stroje)
Hladový algoritmus
Algoritmus (hladový):
- úlohu přidej vždy tam, kde jich je zatím nejméně
- profit?
Věta (slabší odhad): hladový rozvrhovací algoritmus je -aproximační.
Důkaz: uvažme následující diagram:
Z obrázku vyplývá:
- (optimum muselo úlohy také někam dát)
- (optimum muselo použít)
Spojením dostáváme
Věta (silnější odhad): hladový rozvrhovací algoritmus je -aproximační.
Důkaz:
-
- lépe, než rovnoměrně všechny úlohy rozvrhnout nemůžeme
-
- součet všech úloh je alespoň součet před + posledí úloha (vynechám „ocásky“)
Kombinací nerovností dostávám .
Nyní místo odhadu použijeme tyto dva odhady:
Součtem dostáváme
Algoritmus lokálního prohledávání
Pro lokální algoritmus potřebujeme s rozvrhem pracovat formálněji:
- Vstup: strojů, úloh, každá o délce
- Výstup: funkce přiřazující každé úloze startovní čas , koncový čas a stroj
- musí platit že a že se úlohy nepřekrývají
- Cíl: minimalizovat (délka nejdelšího stroje)
Prostě přesouváme stroje, které končí nejpozději někam, aby začínaly dříve a zlepšujeme tím maximum.
Algoritmus (lokální prohledávání):
- najdi libovolný rozvrh bez mezer (i na začátku)
- vezmi libovolné s maximálním
- pokud existuje stroj s délkou rozvrhu , tak přesuň na s minimální délkou
- jinak vystup aktuální rozvrh
(👀):
(👀): Každou úlohu přesuneme nejvýše jednou.
Důkaz: jelikož ji přesouváme na stroj s minimální délkou, tak by musel existovat nějaký s ještě menší, což by byl spor s tím, jak algoritmus funguje (dáváme na nejmenší).
Důsledek: algoritmus je polynomiální.
Věta (silnější odhad pro lokální algoritmus): algoritmus je -aproximační.
Largest Processing Time (LPT)
Algoritmus (LPT):
- úlohy uspořádáme tak, že
- použijeme hladový algoritmus
Věta: LPT je -aproximační algoritmus.
Důkaz: BUNO předpokládejme, že určuje délku rozvrhu (kdyby ne tak na další úlohy zapomenu a řešení se tím nezmění). Rozlišíme případy:
- – stejný výpočet jako předtím, jen silnější nerovnost:
- ,
- stejným výpočtem jako předtím máme
- – LPT vygeneruje optimální rozvrh
- víme, že délka poslední, a tedy každé úlohy je alespoň
- žádný počítač nebude mít 3 úlohy, jelikož by pak byl větší než optimum
- chceme argumentovat, že LPT udělá stejné dvojice jako optimální rozvrh:
- – uvážíme-li pouze prvních úloh, tak optimální rozvrh bude mít alespoň na jednom počítači a ty rozhodně nebudou kratší než dvě nejkratší
- tento rozvrh s méně úlohami je jistě , proto nerovnost platí
- – v optimálním rozvrhu budou mít alespoň počítače dvojici úloh; v jedné z nich bude čtvrtá nejmenší (), která tam bude s nejmenší ()
- obdobně dostaneme všechny další dolní odhady…
- – uvážíme-li pouze prvních úloh, tak optimální rozvrh bude mít alespoň na jednom počítači a ty rozhodně nebudou kratší než dvě nejkratší
Odbočka: online algoritmy
- vstup přichází postupně
- řešení musíme konstruovat postupně po krocích a pak už neměníme
- hladový je online, lokální prohledávání není
- pro : lepší než -aproximační neexistuje (úlohy délky )
- pro je opět hladový nejlepší
- pro to už tak není (existují lepší)
Bin packing
- Vstup:
- Výstup: rozklad tak, že
- součet věcí v každém koši může být nejvýše
- Cíl: minimalizovat (počet košů)
Algoritmus (first fit): dej do prvního koše, do kterého se vejde.
Algoritmus (best fit): dej do nejplnějšího koše, do kterého se vejde.
Věta: oba algoritmy jsou -aproximační (a je to těsný odhad).
Věta: Je NP těžké najít -aproximační algoritmus pro
Důkaz: Je NP těžké rozhodnout, zda , jelikož pomocí něho můžeme přímočaře vyřešit problém dělení množiny na dvě časti se stejným součtem (nastavíme velikost košů na tenhle součet), což je NP těžké.
Věta: Existuje asymptotické aproximační schéma, t. j.
Algoritmus (any fit): dej do nějakého neprázdného koše; pokud nelze, dej ho do nového.
- zahrnuje jak best fit, tak first fit
Věta: každý any fit algoritmus má aproximační poměr .
Důkaz: Pro triviální. Jinak nechť . Musí platit, že (jinak spor s během algoritmu). Posčítáním pro všechny dvojice dostáváme
Hledání disjunktních cest
- Vstup:
- graf (orientovaný/neorientovaný)
- dvojice vrcholů
- kapacita hran
- Výstup:
- (dvojice které spojíme cestou)
- cesty cesta z do tak, že každá hrana leží na nejvýše cestách
- Cíl: minimalizovat
Jednotkové kapacity
Algoritmus (hladový):
- najdeme nejkratší cestu mezi nespojenou dvojicí (přes všechna )
- pokud neexistuje, tak vystoupíme
- odebereme použité hrany
(👀): hladový algoritmus nemá aproximační poměr lepší než :
Délka je . Abychom tuto cestu nezvolili, tak musejí mít ostatní alespoň hran a celkově jich tedy musí být řádově . Naše řešení je tedy o horší.
Věta: Hladový algoritmus s je -aproximační.
Důkaz: BUNO (jinak bychom hned skončili)
- pak (také nějakou najdeme)
Nechť je optimum. Počítejme cesty:
- dlouhé cesty:
- je jich (jinak bych měl více než hran)
- ty mi tedy nic nekazí, jelikož nám stačí, že algoritmus najde nějakou cestu
- krátké cesty:
- vše ok
- má nějakou společnou hranu s nějakou cestou t. ž.
- ve chvíli, kdy algoritmus poprvé vybral cestu delší než už nemohl vybrat , protože tu blokovala nějaká cesta, kterou již předtím zvolil (a ta musí být krátká)
Tedy počet krátkých cest
- – náš algoritmus a optimum vybrali stejnou cestu
- – krátká cesta v našem řešení zablokuje nejvýše ostatních krátkých
Nejednotkové kapacity
Algoritmus (hladový pro nejednotkovou kapacitu):
- zvolíme
- najdeme nejkratší cestu mezi nespojenou dvojicí (přes všechna )
- pokud neexistuje nebo