Cím: Mit rakjunk a hátizsákba, hogyan váltsunk fel pénzt ? II.rész
Szerző(k):  Vízvári Béla 
Füzet: 1996/november, 452 - 457. oldal  PDF  |  MathML 
Témakör(ök): Szakmai cikkek

A szöveg csak Firefox böngészőben jelenik meg helyesen. Használja a fenti PDF file-ra mutató link-et a letöltésre.

 
 
5. Merre menjünk?
 
 

*A cikk első része októberi számunkban (386‐391. o.) olvasható.
El akarunk menni Gyuláról Sopronba a lehető legrövidebb úton. Ebbe a legrövidebb útba esik Kecskemét, majd Győr. Ekkor biztos, hogy az útnak ezen két utóbbi város közé eső szakasza egyben a legrövidebb út Kecskemét és Győr között. Ha ugyanis lenne a két város között egy még rövidebb út, akkor erre kicserélve a Gyula-Sopron út Kecskemét-Győr szakaszát, Gyula és Sopron között egy még rövidebb utat kapnánk.
Ha ki akarunk fizetni 190 Ft-ot a lehető legkevesebb számú pénzdarabbal, és már eldöntöttük, hogy adunk 1 db 100 forintost és 1 db 50 forintost, akkor a maradék 40 Ft-ot a lehető legkevesebb darab pénzzel kell kifizetni, ahogy 40 Ft-ot egyáltalán ki lehet fizetni, különben a megoldásunknál még jobb megoldás létezik, vagyis a mienk nem optimális.
Hasonló a helyzet a hátizsákkal is. Ha bizonyos tárgyakról már eldöntöttük, hogy berakjuk-e azokat, akkor a maradék tárgyakkal a lehető legjobban kell kitölteni a maradék súlykorlátot ahhoz, hogy optimális megoldást kapjunk.
Mindhárom esetben az optimális megoldást döntések sorozatán keresztül tudjuk megtalálni. Például Gyulán úgy döntünk, hogy először Kecskemétre megyünk, majd ott Győr felé vesszük az utunkat, s onnan Sopronba. Tehát az útirány felől döntünk Gyulán, Kecskeméten és Győrben, az út teljes hossza pedig ezen döntések nyomán kialakuló három útszakasz hosszának összege lesz. A 190 Ft kifizetésénél, ha használunk egy 100 és egy 50 forintost, akkor a maradék 40 Ft-ot illetően már szabad kezünk van, és az összesen felhasznált pénzdarab száma a 150 Ft-hoz és a 40 Ft-hoz használt pénzdarabok számának összege lesz. Ha az elvihető tárgyakat két részhalmazra bontjuk fel, és először az egyik részhalmaz felől döntünk, majd csak azután a másikról, akkor az elvitt tárgyak összértéke a két részhalmazból kapott értékek összege lesz. Mindhárom példa azzal a fontos közös tulajdonsággal rendelkezik, hogy az egymást követő döntések eredményei összegződnek.
Az a megfigyelés, hogy a Gyula és Sopron közötti legrövidebb út Kecskemét és Győr közötti szakasza egyben a Kecskemét és Győr közötti legrövidebb út is, és ha 190 Ft kifizetésekor csak 40 Ft maradt, akkor ezt az összeget a lehető legkevesebb pénzdarabbal kell kifizetni, és hogy a második részhalmazzal a lehető legjobban kell kitölteni a hátizsák megmaradt kapacitását, speciális esete egy döntési sorozatokra vonatkozó általános optimalitási feltételnek, amelyet felfedezője után Bellman-elvnek neveznek. A Bellman-elv azt mondja ki, hogy egy optimális döntési sorozat bármely összefüggő részsorozata is optimális a részsorozatot megelőző döntések által kialakított helyzetben. (Az a kifejezés, hogy a ,,részsorozatot megelőző döntések által kialakított helyzetben'' azt jelenti például, hogy a Kecskemét-Győr szakasz optimalitásáról csak akkor beszélhetünk, ha a korábbi döntések hatására Gyuláról eljutunk Kecskemétre.)
Ezen elv segítségével először a (7) feladatot oldjuk meg.*ld. 1996/7. sz. 391. o. Legyen y egy 0 és b közé eső egész. Tekintsük azt a feladatot, amely csak abban tér el (7)-től, hogy az egyenlőség jobb oldalán b helyett y áll:
min(c1x1+c2x2+...+cnxn)a1x1+a2x2+...+anxn=yx1,x2,...,xn0x1,x2,...,xnegész.(8)
A Bellman-elv szerint, ha valamely nemnegatív egész w1,...,wn számokhoz a (7) feladatnak van olyan olyan x1*,...,xn* optimális megoldása, amelyekre teljesül hogy
w1x1*,...,wnxn*,  és  a1w1+a2w2+...+anwn=y,
akkor a w1, ..., wn számok a (8) feladat optimális megoldását adják, továbbá az
x1*-w1, ..., xn*-wn számok pedig annak a (8) alakú feladat megoldását, amelyben az egyenletben a jobb oldal értéke b-y.
Jelölje f(y) a célfüggvénynek az optimális megoldáshoz tartozó értékét. Az f(y) függvény értékét fogjuk kiszámolni minden 0 és b közé eső y egész mellett. Ez első látásra elég nagy pazarlásnak tűnik, hiszen nekünk valójában az f függvény egyetlen értékére van szükségünk, arra nevezetesen, amikor y=b. Látni fogjuk azonban, hogy furcsa módon egyszerűbb valamennyi értéket kiszámolni, mint csak egyetlen egyet.
Ha y=0, akkor nyilvánvalóan az egyetlen megoldás, ami az összes feltételt kielégíti az x1*=0,...,xn*=0. Tehát ez egyben optimális is. Legyen y^ egy 1 és b közé eső egész. Tegyük fel, hogy ismerjük a (8) feladat megoldását az y=0,1,...,y^-1 esetekben. Ekkor az y=y^ jobb oldalhoz tartozó x1*,...,xn* optimális megoldás minden eleme nem lehet 0, azaz legalább 1 pozitív eleme van. Tegyük fel, hogy ez xj*, tehát a Bellman-elv szerint az x1*,...,xj-1*,xj*-1,xj+1*,...,xn* értékek a y^-aj jobb oldalhoz tartozó optimális megoldást adják. Innen az y^ jobb oldalhoz tartozó optimális érték, azaz f(y^) kiszámítására a következő szabályt nyerjük: Meg kell nézni, hogy mekkora az y^-a1, ..., y^-aj, ..., y^-an jobb oldalakhoz tartozó optimális érték, feltéve, hogy a jobb oldal egyáltalán szóba jöhet, azaz a j index mellett y^-aj0 teljesül, ezen értékekhez kell rendre hozzáadni a c1, ..., cj, ..., cn számokat, és az így keletkező mennyiségek közül kell kiválasztani a legkisebbet. Okfejtésünk eredményét az alábbi képletekben fogalmazhatjuk meg:
f(0)=0(9)f(y^)=min{f(y^-aj)+cjy^-aj0,1jn}y^=1,2,...,b.(10)
A (9) képletből kiindulva a (10) azonnal számítható minden y^=1,...,b esetén, ebben a sorrendben.
Érdekes megvizsgálni, hogy így hány művelet elvégzésére van szükség ahhoz, hogy az f(b) értéket meg tudjuk határozni. A b=0 jobb oldalhoz tartozó f(0) érték adott, tehát a (10) képletet pontosan b számú jobb oldal esetén kell kiszámítani. Mindegyikhez legfeljebb n összeadást és az ezek minimumának kiválasztásához n-1 összehasonlítást kell elvégezni. Legfeljebb n összehasonlítás kell annak eldöntésére is, hogy az y^-aj értékek nemnegatívak-e. (Számítógéppel történő számolás esetén ezt valamilyen formában meg kell csinálni.) Tehát a szükséges műveletek mennyiségét nb összeadással és (2n-1)b összehasonlítással becsülhetjük felülről. (Azért szokás a különböző műveleteket külön-külön kezelni, mert számítógépen különböző az elvégzésükhöz elhasznált idő.) A hátizsák feladat korábban említett nehéz volta itt úgy jelenik meg, hogy az elvégzendő műveletek száma arányos a feladat egyik adatával, az egyenlet jobb oldalával. Ha tehát ez nagyon nagy, akkor sok műveletet kell elvégezni. A gyakorlatban az eljárás bizonyos határokon belül gyorsan számol. Arról azonban nincs ismeretünk, hogy ez volna a hátizsák feladat megoldásának leghatékonyabb módszere.
Eddig csak a célfüggvény optimális értékét határoztuk meg, de nem magát az optimális megoldást. Pedig az eljárás melléktermékeként ez is könnyen megkapható. Szükségünk lesz az optimalizálási feladatok kapcsán bevezetett következő jelölésre:
Legyen S egy tetszőleges halmaz, g pedig egy ezen a halmazon értelmezett valós függvény, amelyhez létezik olyan u és v eleme az S halmaznak, hogy a halmaz bármely x eleme esetén g(u)g(x), illetve g(v)g(x), azaz u, illetve v optimális megoldása a
min{g(x)xS},illetvemax{g(x)xS}
feladatnak. Jelölje argmin{g(x)xS}, illetve argmax{g(x)xS} ezen feladatok egy optimális megoldását.
A (10) képletet úgy foghatjuk fel, hogy a g függvény értéke a f(y^-aj)+cj érték, és a függvényt az indexek S={1,2,...,n} halmazán értelmezzük. Ezért, ha az eljárást kiegészítjük a
h(y^)=argmin{f(y^-aj)+cjy^-aj0,1jn}y^=1,2,...,b
utasítással, akkor azon változók indexeit őrizzük meg, amelyeket 1-gyel megnövelve kapjuk az új jobb oldal optimális megoldását. Ezért a keresett optimális megoldást úgy állíthatjuk elő, hogy b-ből visszafelé haladva megszámláljuk, hogy melyik változót hányszor kellett növelni. Innen az alábbi algoritmust kapjuk:

begin
for j:=1 to n do xj=0;
y:=b;
while y>0 do
begin
xh(y):=xh(y)+1;
y:=y-ah(y);
end

end

A módszer tárgyalásakor kihasználtuk, hogy a legkisebb együttható, azaz a1, éppen 1. Ezért bizonyos, hogy bármely b jobb oldal mellett vannak olyan x1, ..., xn nemnegatív egészek, amelyek kielégítik az egyenletet. A módszer kis módosítással akkor is alkalmazható, ha ez a feltétel nem teljesül. Legyen M egy nagyon nagy szám, amely biztosan nagyobb, mint bármely optimális megoldás értéke. Ekkor az induló értéket megadó (9) képletet így kell módosítani:
f(0)=0,f(y)=M,y=1,...,b(11)
Ha az algoritmus végén valamely y esetén f(y) még mindig M, akkor az egyenlet ezen jobb oldal mellett nemnegatív egészekkel nem elégíthető ki.
Befejezésül a Bellman-elvet a hátizsák feladat megoldására használjuk fel. A feladat adatairól feltesszük, hogy pozitívak. Most óvatosabban kell eljárnunk, mint előzőleg. Egy bizonyos tárgy elvitelére vonatkozó döntés meghozatalakor ugyanis nem elég csak azt figyelembe venni, hogy a hátizsák kapacitásának egy meghatározott y részét hogyan lehet a legjobban kitölteni, hanem biztosítani kell, hogy ebben a legjobb kitöltésben a vizsgált tárgy ne legyen benne. Ezért két részre osztjuk a tárgyakat. Az egyik részről éppen most döntünk, ezek lesznek az 1,...,k,k+1 indexűek, és a másik részről azt gondoljuk, hogy már döntöttünk. Az utóbbiak a k+2,...,n indexűek.
Ennek megfelelően legyen k egy 1 és n közé eső, y pedig ismét egy 0 és b közé eső egész. Jelölje f(k,y) a (1) feladat azon részfeladatának optimális célfüggvényértékét, amelyben csak az első k változót vesszük figyelembe, a jobb oldal pedig y. Tehát
f(k,y)=max(c1x1+c2x2+...+ckxk)a1x1+a2x2+...+akxkyx1,x2,...,xk=0vagy1.(12)

Az első észrevétel, amit tehetünk, hogy az f(1,y) függvényt könnyű meghatározni, hiszen
f(1,y)=maxc1x1a1x1=yx1=0  vagy  1.(13)
A célfüggvény monoton növő az egyetlen x1 változóban, így ezt olyan nagynak kell megválasztani, amilyen nagynak csak lehet, azaz a változó optimális értéke, x1*, pontosan akkor 1, ha a1y, különben pedig 0. Eszerint
f(1,y)={0,ha  y<a1
 
c1ha  ya1.
(14)
Tegyük fel most már, hogy az f(k,y) függvény értékét valamely rögzített k mellett valamennyi y-ra ismerjük. Próbáljuk meghatározni az f függvény értékeit, ha az első változója éppen k+1. A k+1 indexű tárgyat csak akkor lehet betenni a hátizsákba, ha a még felhasználható súlykorlát, y legalább akkora, mint a tárgy súlya, azaz ak+1. Ha ez nem teljesül, akkor az első k tárggyal pontosan akkora érték érhető el, mint az első k+1 tárggyal. Ha viszont a feltétel teljesül, akkor mindkét lehetőséget, nevezetesen a tárgy elvitelét és otthon hagyását is számba kell venni. Tehát
f(k+1,y)={f(k,y),ha  y<ak+1max{f(k,y),f(k,y-ak+1)+ck+1},ha  yak+1.(15)

Ismét megállapítható, hogy az f(1,y) (y=0, ..., b) értékek ismeretében az f(k,y) (y=0, ..., b) értékek egyszerűen számíthatók k=2, ..., n esetén, k értékeinek növekvő sorrendjében. Tehát a (12) és (13) képletek a hátizsák feladat egy megoldási módszerét adják.
Az f(k,y) érték meghatározásához legfeljebb 2 összehasonlításra és egy összeadásra van szükség. Ha csak az eredetileg kitűzött hátizsák feladatot akarjuk megoldani, akkor az f(k,y) függvény értékeit elegendő csak k=1,...,n-1 mellett meghatározni, valamint külön az f(n,b) értéket. Tehát 2nb-2b+2n, illetve nb-b+n felső korlát a szükséges összehasonlítások, illetve összeadások számára. Ha azonban kiváncsiak vagyunk arra, hogy a súlykorlát hogyan befolyásolja az optimális megoldást, akkor valamennyi y mellett meg kell határozni f(n,y)-t is. Tehát az utóbbi esetben az eljárás egyszeri végrehajtásával b+1 különböző jobb oldalra tudjuk a feladatot megoldani.
Amíg tehát a műveletek nagyságrendje azonos a pénzváltási probléma megoldásához szükséges műveletekével, addig más a helyzet a szükséges memóriával. Az előző feladatnál mindössze két b+1 hosszú vektorra volt szükségünk, egy az f függvény, egy pedig az optimális megoldást leíró h vektor számára. Mostani feladatunknál azonban több memóriára van szükség. Első ránézésre az f függvény tárolása egy n×(b+1) méretű tömböt igényel. Azonban vegyük észre, hogy az f(k+1,.) függvény értékeinek meghatározásakor mindig csak az f(k,.) függvény értékeit használjuk, és az f(1,.), ..., f(k-1,.) függvények értékei soha többet nem jönnek elő. Tehát úgy járhatunk el, hogy először kiszámítjuk f(1,.)-et, majd ebből f(2,.)-t. Ezután már f(1,.)-re nincs szükségünk, tehát ennek a helyét használhatjuk f(3,.) meghatározásához, ezután f(2,.) helyét f(4,.)-hez, és így tovább. Tehát az f függvényhez összesen két b+1 tömbre van szükség. Nem így az optimális megoldás tárolásához, ahol valóban kell az n×(b+1) méretű tömb. Jelölje x*(k,y) az optimális megoldást, ami persze szintén függvénye a változók számának és a jobb oldalnak. Ekkor a (15) képletből adódóan
x*(k+1,y)={0,ha  y<ak+1
 
0,ha  yak+1  és  f(k,y)>f(k,y-ak+1)+ck+1
 
1,ha  yak+1  és  f(k,y)f(k,y-ak+1)+ck+1.
(16)
Ekkor a tényleges x* optimális megoldást úgy kapjuk, hogy először eldöntjük xn értékét, ami természetesen az
xn*=x*(n,b)
egyenlet alapján történik. Ezután döntünk xn-1 felől
xn-1*=x*(n-1,b-anxn*)
szerint, és így folytatjuk, míg végül az
x1*=x*(1,b-a2x2*-...-anxn*)
teljes megoldást meghatároztuk.
Tehát legalább (n+1)×(b+1) méretű memóriára van szükségünk. Ha nem egy feltételünk volna, hanem több, például a turista nemcsak az elviendő tárgyak súlyát, hanem térfogatát is korlátozná, akkor a memória igény és persze vele együtt a számítási igény is megsokszorozódna, ezért ekkor már más megoldási módszereket kellene használni.
 

Vizvári Béla, Budapest, ELTE

*1

*2