2. Problém přelévání vody





Zadání:

Základní problém je definován takto: K dispozici jsou dva kýble (předem daných obecně rozdílných objemů), vodovodní kohoutek a kanál. Na počátku jsou oba kýble prázdné. Vaším úkolem je docílit toho, aby v jednom kýblu byla voda o předem stanoveném objemu, přičemž můžete pouze naplnit plný kýbl z kohoutku, vylít celý kýbl do kanálu a přelít jeden kýbl do druhého tak, aby druhý kýbl nepřetekl. Problém lze zobecnit tím, že připustíme užití většího počtu kýblů, aby na počátku řešení byla v kýblech nějaká voda, a že předepíšeme koncový objem vody v každém kýblu.
Navrhněte a implementujte heuristiku řešící zobecněný problém dvou kýblů. Heuristiku otestujte na následujících příkladech:

Kýble (objem) 14 10 6 2 8
Počátek 0 0 1 0 0
Stav 1 12 6 4 1 8
Stav 2 14 4 5 0 4
Stav 3 12 6 6 2 4
Stav 4 0 2 1 2 8


Kýble (objem) 15 12 8 4 6
Počátek 0 0 0 0 0
Stav 1 5 5 5 0 1
Stav 2 12 1 3 4 5
Stav 3 11 1 3 4 5
Stav 4 3 12 4 0 6
Stav 5 2 0 4 3 6


Kýble (objem) 14 10 12 3 8
Počátek 0 0 0 0 0
Stav 1 13 9 12 2 7
Stav 2 1 5 5 3 4
Stav 3 0 9 6 3 1
Stav 4 12 0 12 0 2
Stav 5 7 3 7 0 0
Stav 6 7 0 7 0 7


Zpráva bude obsahovat:


Řešení:

Tento problém se standardně řeší pomocí prohledávání stromu do šířky (DFS). Bruteforce spočívá v projití celého stavového prostoru a hledání prvního nebo nejlepšího řešení, což je časově velmi náročné. Při použití heurestiky nahradíme klasickou frontu frontou prioritní, kde zkoumané stavy seřadíme podle určitého kriteria. Vlastní algoritmus je pak již známý DFS. V mém programu jsou implementovány dva způsoby ohodnocení:

První ohodnocuje řešení podle počtu správně naplněných kýblů:
cena = SUMi ( actuali == cili )

Druhé ohodnocení je dáno euklidovskou vzdáleností aktuálního řešení od cílového řešení:
cena = - SQRT ( SUMi ( actuali - cili ) )
Kde minus před odmocninou je z důvodu opačného ohodnocování oproti prvnímu řešení (fronta řadím sestupně). Odmocninu v programu při ohodnocování nepočítám, protože výsledek neovlivní.


Naměřené hodnoty:

Výsledné hodnoty jsou uvedeny pro obě použité varianty ohodnocení. První je počet již seřazených kýblů a druhý euklidovská vzdálenost. Při programování bylo ozkoušeno více algoritmů pro ohodnocení než uvedené dva, žádný však na zadaných instancích nebyl viditelně rychlejší než naše první použitá metoda.

objem 14 10 6 2 8 manipulací uzlů
počátek 0 0 1 0 0 "1" "2" "1" "2"
konec 1 12 6 4 1 8 13 20 121 143
konec 2 14 4 5 0 4 11 21 90 613
konec 3 12 6 6 2 4 10 8 24 10
konec 4 0 2 1 2 8 4 4 6 6


objem 15 12 8 4 6 manipulací uzlů
počátek 0 0 0 0 0 "1" "2" "1" "2"
konec 1 5 5 5 0 1 28 44 572 32001
konec 2 12 1 3 4 5 33 33 285 29151
konec 3 11 1 3 4 5 20 33 228 22197
konec 4 3 12 4 0 6 8 17 19 2035
konec 5 2 0 4 3 6 19 22 127 2381


objem 14 10 12 3 8 manipulací uzlů
počátek 0 0 0 0 0 "1" "2" "1" "2"
konec 1 13 9 12 2 7 17 36 245 3884
konec 2 1 5 5 3 4 26 55 414 1226
konec 3 0 9 6 3 1 25 28 195 1768
konec 4 12 0 12 0 2 8 12 24 105
konec 5 7 3 7 0 0 10 15 80 1422
konec 6 7 0 7 0 7 13 52 105 4303



Závěr:

Použití heuresitky nám nezaručuje nalezení nejlepšího řešení. Tato nevýhoda je však kompenzována velikým zrychlením oproti procházení celého stromu. Problém je nalézt vhodnou ohodnocovací funkci. Ze zde uvedených dvou možných řešní je jasně lepší ohodnocování podle počtu kýblů v koncovém stavu. Jistě existuje lepší algoritmus, tento však při své jednoduchosti podavá vynikající výsledky.


Přílohy:

zdrojový kód voda.cpp
zakompresovaná data použitá v analýze data.zip