Professional Documents
Culture Documents
Darbo vadovas:
lekt. Irmantas Radavičius (parašas)
Recenzentas:
asist., dr. Julius Andrikonis (parašas)
Vilnius
2019
Santrauka
Darbe analizuojami du algoritmai, tai klasikinis Vengrų algoritmas, bei dinaminis Vengrų
algoritmas. Vis didėjantys duomenų kiekiai, su kuriais dažniausiai nuolatos vyksta pakeitimai,
priverčia pasirinkti geresnius sprendimo būdus nei kad pasikeitus duomenims problemą spręsti iš
naujo.
Šio darbo tikslas – apžvelgti dinaminį Vengrų algoritmą ir palyginti jį su statiniu. Gauti
rezultatai leidžia nuspręsti, kada geriau pasirinkti dinaminį, o kada statinį Vengrų algoritmą.
Darbo pirmoje dalyje supažindinama su reikalingomis sąvokomis bei sprendimo metodais, o
antroje dalyje pateikiama algoritmų implementacija. Svarbiausia vieta yra trečioje dalyje, kur
atliekami eksperimentai bei gaunami rezultatai, kurie leidžia teigti ar dinaminis Vengrų algoritmas
yra vertas implementacijos ir jei taip, tai kada.
2
Summary
The paper analyzes two algorithms – the classical Hungarian algorithm and it’s dynamic
counterpart, the dynamic Hungarian Algorithm. The ever increasing amount of data, which is
constantly being accessed and modified, makes us choose better ways than to solve the problem
from scratch each time.
The aim of this work is to look at the dynamic Hungarian algorithm and compare it to the
static one. The results that we get will let us decide when to choose each algorithm. At the start
of this paper the most important concepts and notations are introduced. Then we analyze the
algorithms and their implementations. In the most important part, the third section of this paper
we will perform experiments and get results that will let us decide if the dynamic Hungarian
algorithm is worth implementing and if yes, then when.
3
Turinys
ĮVADAS ................................................................................................................................. 5
1. PRISKYRIMO PROBLEMA ............................................................................................ 7
1.1. Priskyrimo problemos apibrėžimas ............................................................................. 7
2. ALGORITMAI ................................................................................................................ 11
2.1. Vengrų algoritmas ..................................................................................................... 11
REZULTATAI IR IŠVADOS.............................................................................................. 33
ŠALTINIAI ........................................................................................................................ 355
4
ĮVADAS
Pradėjus vystytis technologijoms, daugelį darbo vietų pradėjo keisti mašinos arba
programinė įranga. Ji gali visiškai pakeisti žmogų arba jam pagelbėti, kas žymiai padidina
efektyvumą ir sumažina produkcijos kaštus. Tačiau norint, kad programinę įrangą būtų verta
įsigyti, didelis dėmesys yra kreipiamas į algoritmus, kurie atlieka ir įgyvendina norimą
funkcionalumą.
Turint programinę įrangą, kuri naudoja efektyvius algoritmus, galima sutaupyti daug
resursų. Resursai gali būti pinigų, žaliavų ar kitų nematerialių formų pavidalu. Didelė dalis darbo
vietų, kur žmogus turi atlikti kokį nors darbų paskirstymą, gali būti automatizuota. Tai ir yra
daroma šiais laikais, nes kuo didesnis darbuotojų ir darbų skaičius, tuo ilgiau užtrunka tą
paskirstymą padaryti paprastam darbuotojui. Daugelyje atvejų algoritmas ne tik paskirstytų
darbus, tačiau rastų optimaliausią paskirstymą, kad resursų, įgyvendinti tiems darbams, būtų
sunaudota mažiausiai.
Algoritmas yra instrukcijų rinkinys, skirtas kokios nors užduoties sprendimui. Turint
užduotį, kurią reikia įgyvendinti, dažniausiai galima pasirinkti ne iš vieno, bet daugelio algoritmų.
Tai yra svarbu dėl to, kad turint kelis algoritmus, galima juos palyginti ir pasirinkti optimalų
variantą sau.
Į klausimą, kaip palyginti skirtingus algoritmus, sprendžiančius tą pačią užduotį, atsako
sudėtingumo teorija. Svarbiausi palyginimo kriterijai: algoritmo veikimo laikas, sunaudotos
atminties apimtis, ar jis apskritai baigia darbą ir ar galima jį vykdyti lygiagrečiai naudojant kelis
kompiuterius [AB09].
Taip pat aktualus klausimas, ką daryti, jeigu turimas didelis duomenų kiekis, kuris visada
keičiasi. Paprasčiausias būdas būtų paleisti turimą algoritmą iš naujo, tačiau turint daug duomenų
ir daug pakeitimų, tai gali būti labai lėtas būdas gauti sprendimą. Vienas iš pasirinkimų yra naudoti
dinaminius algoritmus, kurie, turint kažkokius duomenis su jau gautu sprendimu, gali atitinkamai
pakeisti kintamuosius ir išspręsti tik reikiamą dalį užduoties su pasikeitusiais duomenimis.
Nors ir ne visada, tačiau dažniausiai, kai užduočiai spręsti yra pasirenkamas algoritmo
automatizavimas, dirbama su dideliu duomenų kiekiu arba yra reikalingas labai greitas to
paskirstymo laikas. Vienas iš paskirstymo pavyzdžių, kai reikalingas labai spartus algoritmas, yra
transporto sektorius. Staiga užsidaręs kelias gali daryti įtaką transportavimo kaštams.
5
Jeigu taip atsitinka ir duomenys pasikeičia, galima priskyrimo užduotį spręsti iš naujo,
tačiau turint didelį duomenų kiekį kiekvieną kartą spręsti iš naujo gali būti prastas pasirinkimas.
Panaudojus dinaminį algoritmą, kuris leistų pataisyti turimą sprendimą atsižvelgiant į
pasikeitusius duomenis, būtų galima sutrumpinti algoritmo veikimo laiką.
Darbo tikslas
Sukurti algoritmą, kuris pasinaudodamas duomenimis apie grafą galėtų parinkti optimalesni
sprendimą kada naudoti statinį, o kada dinaminį Vengrų algoritmą.
Uždaviniai
• Sukurti įrankį, kuris padėtų sugeneruoti duomenis bei palyginti algoritmus;
• Implementuoti statinį ir dinaminį Vengrų algoritmus;
• Atlikti eksperimentus;
• Remiantis eksperimentų duomenimis implementuoti algoritmą, kuris galėtų parinkti
reikiamą sprendimo būdą atsižvelgiant į grafą.
Šiame darbe implementuoti du algoritmai skirti spręsti priskyrimo problemą. Vienas
statinis, o kitas dinaminis, kuris bando pataisyti statinio algoritmo pirmutinį sprendimą. Darbe bus
palyginti šie algoritmai ir bus atlikti eksperimentai norint sužinoti, kokiomis sąlygomis yra geriau
naudoti dinaminį, o kada statinį. Taip pat bus implementuotas algoritmas, kuris panaudodamas
mūsų eksperimentų metu gautus rezultatus pats parinks geresnį sprendimo būdą atsižvelgdamas į
grafą. Darbas sudarytas iš 3 dalių. Pirmame skyriuje apžvelgta, kas yra priskyrimo problema, kaip
ji užrašoma bei kokios grafo struktūros naudojamos norint ją užrašyti ir išspręsti. Toliau darbe,
antrame skyriuje, aprašomi pasirinkti algoritmai bei jų implementacijos detalės. Trečiame skyriuje
aprašomi reikalingi eksperimentai duomenims, jų generavimo būdas, įrankis palyginti algoritmus
ir eksperimentų rezultatai.
6
1. PRISKYRIMO PROBLEMA
Šiame skyriuje yra aprašoma, kas yra priskyrimo problema, pateikiamas jos aprašymas bei
pavyzdys. Taip pat skyriuje supažindinama su pagrindiniais terminais ir sąvokomis, kurios
naudojamos algoritmuose.
Tomas 1€ 4€ 5€
Jonas 5€ 7€ 6€
Petras 5€ 8€ 8€
7
Kaip matoma 1 lentelėje, kiekvienas darbuotojas atlieka darbus už tam tikrą kainą. Iš viso
galimi 6 paskirstymai. Tačiau iš jų tik du – optimalūs. Pirmas, kuriame Tomas turėtų plauti grindis,
Jonas indus, o Petras langus. Šis paskirstymas lentelėje paryškintas. Antras paskirstymas, kuriame
Tomas turėtų plauti langus, Jonas indus, o Petras grindis. Abu darbų paskirstymai kainuoja 15
eurų.
1
Grafas – tam tikrų viršūnių, sujungtų briaunomis ir/arba lankais, rinkinys. Grafu vadinsime pora G = (V, E),
kur V kokia nors aibė, o E – aibės V elementų porų aibė. Aibės V elementai vadinami grafo G viršūnėmis, o aibės E
elementai – briaunomis [BM76].
8
1.2.3. Priskyrimo problemos užrašymas grafų poravimo pavidalu
Priskyrimo problemos užrašymui naudojame grafo briaunų kainų matrica.
Kaip matome, 2 pav. yra nepilnas dvidalis grafas. Jo briaunos sujungia darbuotojus (viršūnės
kairėje) su darbais (viršūnės dešinėje).
9
Auginantis takas yra toks alternuojantis takas, kuris prasideda ir baigiasi nesuporuota
viršūne. 3 pav. toks pats takas kaip ir prieš tai buvęs alternuojantis.
Vengrų medis yra sudarytas iš visų alternuojančių takų, prasidedančių iš kurios nors
nesuporuotos viršūnės. Auginančio tako ieškojimas yra alternuojančių takų peržiūra grafo
paieškos platyn principu, o procesą galima pavadinti Vengrų medžio auginimu. Vengrų medį,
prasidedantį viršūnėje v3, galime pamatyti 4 pav.
3 pav. Dvidalis grafas su suporuotomis 4 pav. Vengrų medis prasidedantis nuo v3 viršūnės
ir nesuporuotomis viršūnėmis
10
2. ALGORITMAI
Šiame poskyryje supažindinama su algoritmais priskyrimo problemai spręsti, kurie naudoja
grafų poravimo metodą. Šiame darbe implementuoti ir palyginti du algoritmai. Pirmiausia, tai
klasikinis Vengrų algoritmas su greitesne implementacija ir dinaminis Vengrų algoritmas, kuris
naudoja statinio algoritmo sprendinį, kad pasikeitus duomenims galėtų greičiau pataisyti sprendinį,
užuot iš naujo sprendęs visą uždavinį pasinaudojus statinį algoritmą.
11
2.1.2. Algoritmas
Įvestis: Dvidalis grafas, {V, U, E} (kur |V| = |U| = n) ir 𝑛 × 𝑛 matricos svorio matrica
Išvestis: pilnas suporavimas M
1) Inicializacija:
a) Pradedame nuo tuščio suporavimo M0 = ∅
b) Priskiriame galimas reikšmes dualiems kintamiesiems αi ir βj pagal taisykles:
∀vi ∈ V, αi = 0
∀ui ∈ U, βj = min (cij)
2) Atliekame n pakartojimų algoritmo žingsnio Stadiją.
3) Grąžiname suporavimą po n-tosios stadijos: M = Mn
Stadija:
1. Paskiriame kiekvieną nesuporuotą viršūnę iš V kaip Vengrų medžio šaknį.
2. Auginame Vengrų medžius nesuporuotose viršūnėse lyginamajame subgrafe. Viršūnių vi
indeksus i, sutinkamus Vengrų medyje, paskiriame aibei I*, o indeksus j viršūnių uj aibei
J*. Jei randamas auginantis takas, einame į 4 žingsnį, jei ne, medžiai negali būti daugiau
auginami, einame į 3 žingsnį.
3. Keičiame dualiuosius kintamuosius α ir β kaip parodyta žemiau, kad galėtume pridėti
naujas briaunas į lyginamąjį subgrafą. Tada grįžtame į 2 žingsnį, kad toliau ieškotume
auginančio tako.
1
Θ= min (𝑐𝑖𝑗 − α𝑖 − βj )
2 𝑖∈𝐼 ∗ ,𝑗∉𝐽∗
α + Θ 𝑖 ∈ 𝐼∗
α𝑖 ← { 𝑖
α𝑖 − Θ 𝑖 ∈ 𝐼 ∗
α + Θ 𝑗 ∈ 𝐽∗
βj ← { 𝑖
α𝑖 − Θ 𝑗 ∈ 𝐽 ∗
4. Auginame esamą poravimą apkeisdami suporuotas ir nesuporuotas briaunas auginančiame
take.
Taip pat Θ gali būti efektyviau apskaičiuotas per O(n) vietoj O(𝑛2 ) turint atsilikimo (angl.
slack) kintamuosius ieškant augančio tako 2 žingsnyje. Ieškodami kiekvienai viršūnei uj,
1
slack(𝑢𝑗 ) = min∗ (𝑐𝑖𝑗 − α𝑖 ). Tada Θ = min(𝑠𝑙𝑎𝑐𝑘(𝑢𝑗 ). Šio Vengrų algoritmo sudėtingumas
𝑖∈𝐼 2 𝑗
12
2.2. Inrekementinis algoritmas
2.3. skyriuje aprašytas Dinaminis Vengrų algoritmas kaip pagrindą naudoja inkrementinės
priskyrimo problemos algoritmą [IG07], dėl to šiame poskyryje jis bus trumpai apžvelgtas.
2.2.1. Apibrėžimas
Inkrementinėje priskyrimo problemoje, turint svorinį dvidalį grafą ir jau turimą suporavimo
sprendimą, norime gauti maksimalų suporavimą tada, kai prie esamo grafo bus pridėta nauja
viršūnių pora, po viršūnę abiejuose grafo aibėse, kurios bus sujungtos briaunomis su visomis
kitomis kitos aibės viršūnėmis. Ši problema apima scenarijų, kai gali atsirasti papildomi
kintamieji, tačiau neapima realesnio varianto, kai esamų kintamųjų kainos (svoriai) gali pasikeisti.
Inkrementinis algoritmas pirmiausia apskaičiuoja naujas dualiųjų kintamųjų α𝑛+1 ir
β𝑛+1 reikšmes. Kiti dualūs kintamieji galutiniame sprendinyje vis dar yra teisingi. Ir tada
atliekama viena Vengrų algoritmo stadija, kad būtų rastas auginantis takas tarp naujų viršūnių v𝑛+1
ir u𝑛+1 . Jeigu bus atliekamas tik vienas pakeitimas, algoritmo sudėtingumas yra O(𝑛2 ).
2.2.2. Algoritmas
Įvestis: priskyrimo problemos dvidalis grafas {V, U, E} (kur |V| = |U| = n + 1) ir 𝑛 + 1 × 𝑛 +
1 svorio matrica; Optimalus sprendimas prieš tai buvusio 𝑛 × 𝑛 grafo su finalinėmis dualių
kintamųjų α𝑖 ir β𝑗 , kur i ∈ 1...n ir j ∈ i...n, reikšmėmis.
Išvestis: optimalus suporavimas M 𝑛 + 1 × 𝑛 + 1 problemai.
1) Inicializacija:
3) Grąžiname suporavimą M.
13
2.3. Dinaminis algoritmas
Šiame skyriuje aprašytas dinaminis Vengrų algoritmas, kuris apima problemą, kai turimo
dvidalio grafo briaunų svoriai keičiasi [GAM07].
2.3.1. Apibrėžimas
Šio algoritmo tikslas yra efektyviai pataisyti priskyrimo problemos sprendinį, kai turima
kainų matrica pasikeitė. Problema yra generelizuota inkrementinio priskyrimo versija, kurią
svarstė [IG07], kad galima būtų pritaikyti atvejams, kai briaunų svoriai keičiasi. Pagrindinė
algoritmo strategija yra sekti vietą, kurioje pasikeitę duomenys. Kai žinome, kad pasikeitė kurios
nors viršūnių briaunų kaina, tą viršūnę išimame iš galutinio turimo poravimo. Tada atnaujiname
dualių kintamųjų reikšmes pagal kitame skyriuje matomas formules ir praleidžiame vieną Vengrų
algoritmo stadiją.
Kadangi įvykdoma tik viena Vengrų algoritmo stadija, problemos sprendimo asimptotinis
sudėtingumas yra O(𝑛2 ). Dinaminis Vengrų algoritmas taip pat gali būti lengvai panaudojamas,
jeigu pasikeitė k skaičius stulpelių ar eilučių. Tada visos viršūnės yra išimamos iš galutinio
poravimo, atnaujinamos dualių kintamųjų reikšmės ir atliekamas Vengrų algoritmo stadijų k
skaičius. Tokiu atveju asimptotinis algoritmo sudėtingumas yra O(k𝑛2 ).
2.3.2. Algoritmas
Įvestis: priskyrimo problemos dvidalis grafas {V, U, E} (kur |V| = |U| = n) ir 𝑛 × 𝑛 svorio
matrica; Optimalus sprendimas prieš tai buvusio 𝑛 × 𝑛 grafo su pilnu suporavimu 𝑀∗ finalinėmis
dualių kintamųjų α𝑖 ir β𝑗 reikšmėmis; Eilutė ar stulpelis kur buvo atlikti pakeitimai.
Išvestis: optimalus suporavimas M naujai problemai su pasikeitusiais briaunų svoriais.
1) Inicializacija:
14
3) Grąžiname suporavimą M.
2.3.3. Pavyzdys
Toliau galime pamatyti kaip veikia dinaminis algoritmas. Grafe suporuotos viršūnės
vaizduojamos pilnomis briaunomis, o nesuporuotos, tačiau leistinos viršūnės, taškinėmis
briaunomis. 5 pav. matome optimalų sprendinį, kurio suma yra 13.
Galime manyti, kad vieno iš stulpelių suma pasikeičia. Pagal algoritmo apibrėžimą viršūnės
poravimas sunaikinamas, tai galime pamatyti 6 pav. β4 reikšmė yra iš naujo apskaičiuojama pagal
2.3.2 skyriuje esančią formulę. Nauja reikšmė matoma 7 pav., kuri taip pat suteikia leistiną
briauną, matomą grafe v2, u4.
Dabar prasideda pagrindinis algoritmo žingsnis, kuris įvykdo vieną statinio Vengrų
algoritmo stadiją. Auginančio tako paieška prasideda tik iš v2. Kadangi takas nerandamas, reikia
atnaujinti viršūnių dualiųjų kintamųjų reikšmes, ką matome 8 pav. Tada takas ieškomas toliau ir
randamas (v4, u5, v6, u2, v5, u4). Esamas poravimas yra auginamas šiuo taku apkeičiant suporuotas
ir nesuporuotas briaunas, kaip matoma 9 pav. Galutinis optimalus poravimas, kurio suma 12,
matomas 10 pav. Pavyzdys sudarytas naudojant [GAM07].
15
6 pav. Pakeičiamas kainų matricos stulpelis
16
8 pav. Nerandamas auginantis takas, atnaujinamos reikšmės
17
10 pav. Galutinis grafo suporavimas
18
3. ALGORITMŲ PALYGINIMAS
Šiame skyriuje aprašomas reikalingų testavimui duomenų generatorius, kuris leidžia mums
greitai gauti didelius grafus ir atlikti norimas modifikacijas. Aprašoma pagrindinė aplinka, kurioje
buvo testuojami algoritmai, taip pat pagrindinės jų implementacijos detalės. Galiausiai
apžvelgsime pagal tam tikrus kriterijus palygintų algoritmų eksperimentų rezultatus.
19
11 pav. Pavyzdinis gretimumo sąrašas
Norint iš duotų duomenų sugeneruoti grafą, labiau yra patartina naudoti gretimumo sąrašą, nes
jo saugojimas užima mažiau vietos. Mūsų atveju naudosime paprastesnį gretimumo matricos
variantą – kainų matricą. Eilutės atitinka vieną dvidalio grafo aibę, stulpeliai kitą, o matricos
skaičiai – briaunų svorį jungiantį viršūnes.
20
o Stulpelio elementų pakeitimas, kai norimų pakeisti elementų kiekis stulpelyje
nurodomas procentais.
• Matricos generavimas, kurios briaunų svoriai yra visi unikalūs;
• Didelio kiekio skirtingų matricų generavimas ir pakeitimai, pagrindiniai parametrai
nurodomi programos viduje, nėra galimybės valdyti per konfigūracinius failus;
• Didelio kiekio skirtingų matricų generavimas į skirtingas direktorijas, pagrindiniai
parametrai nurodomi programos viduje.
Programa apima galimybę nesunkiai sugeneruoti norimą matricą ar atlikti pakeitimus
nežiūrint į programinį kodą. Tačiau, jei norima generuoti didelius matricų kiekius ar atlikti
pakeitimus, kur reikia nurodyti daug direktorijų ar failų, reikia pakeisti parametrus programos
funkcijų viduje.
Šio darbo eksperimentų generavimui naudota funkcija generateAdvancedSets, kuri, jos
viduje nurodžius direktorijas, nuskaito pagrindines matricas, pakeičia nurodytą elementų kiekį ir
išspausdina viską į failus. Atitinkamai nuo matricos dydžio bei pakeitimų skaičiaus, matricų
kiekis, kuris užima apie 60GB bei turi daug pakeitimų, šiuo kompiuteriu užėmė iki valandos laiko.
Galimi patobulinimai būtų visus parametrus iškelti į konfigūracinį failą iš kurio būtų
skaitoma.
2
Implementacija - https://github.com/KevinStern/software-and-algorithms/blob/master/
src/main/java/blogspot/software_and_algorithms/stern_library/optimization/HungarianAlgorithm.java
21
1. Gauname statinio Vengrų algoritmo objektą, originalią kainų matricą bei kainų
matricą su atliktais joje pakeitimais;
2. Atnaujiname Vengrų algoritmo objekto kainų matricą į naują;
3. Patikriname skirtumus tarp senos kainų matricos ir naujos. Randame pasikeitusias
vietas (šiuo atveju stulpelius) ir reikiamose vietose sunaikiname poravimus;
4. Pagal straipsnyje [GAM07] aprašytas taisykles atnaujiname dualius kintamuosius;
5. Paleidžiame statinį Vengrų algoritmą nusiųsdami reikšmę false, kad nebūtų sugadinti
pradinio sprendinio parametrai.
Pagrindinė programos klasė Main turi galimybę atlikti tokius veiksmus:
• Nuskaityti matricą iš nurodytos vietos;
• Praleisti didelį kiekį testų statiniam Vengrų algoritmui;
• Praleisti didelį kiekį testų statiniam bei dinaminiam Vengrų algoritmams. Gautus
duomenis apie laiką bei kitus norimus parametrus (kaip kad kurios viršūnės
suporuotos su kuriomis) išsisaugoti bei išspausdinti į norimą vietą (ekraną arba failą);
• Galimi du išspausdinimo būdai:
1. Išspausdinama į nurodytą failą ar failus suprantamais žodžiais bei
komentarais apie gautus parametrus po algoritmų suveikimo;
2. Išspausdinama į nurodytą failą ar failus gautus duomenis, kad būtų galima
implementacija su kitomis programomis.
Kad gautume kuo tikslesnį algoritmo įvykdymo laiką, naudojame Java funkciją
System.nanoTime(). Taip pat laiką skaičiuojame nuo tada, kai pradeda veikti algoritmas, o ne kai
sukuriamas klasės objektas bei priskiriami kintamieji.
Galiausiai atėmę iš dabartinio laiko pradinį ir padalinę iš milijono gauname apytikslį laiką
milisekundėmis, kiek laiko užtruko algoritmai spręsdami užduotį.
3.5. Eksperimentai
Eksperimentai atlikti norint gauti kuo tikslesnius rezultatus valdant tam tikrus parametrus.
Pagrindiniai eksperimentų parametrai buvo:
• Stulpelių pakeitimo skaičius;
• Stulpelio elementų pakeitimo skaičius;
• Svoriai skiriami briaunoms kainų matricoje;
• Viršūnių skaičius.
Kaip matome N pav. naudojama viršūnių skaičių aibė buvo sudaryta iš 7 elementų.
Kiekvienam viršūnių skaičiui buvo sugeneruojami keturi pradiniai failai, kurie sekė tokias
taisykles:
22
𝑛 𝑛
• File1 – matrica dydžio × , kur n – bendras viršūnių skaičius, briaunų svoriai tarp
2 2
1 ir 10;
𝑛 𝑛
• File2 – matrica dydžio × , kur n – bendras viršūnių skaičius, briaunų svoriai tarp
2 2
1 ir 100;
𝑛 𝑛
• File3 – matrica dydžio × , kur n – bendras viršūnių skaičius, briaunų svoriai tarp
2 2
1 ir 1000;
𝑛 𝑛
• File4 – matrica dydžio × , kur n – bendras viršūnių skaičius, briaunų svoriai visi
2 2
unikalūs.
Turint pagrindinius failus, galima atlikti reikiamus pakeitimus. Atlikti pakeitimai buvo pagal
šias taisykles, kur N – viršūnių skaičius:
Kaip pavaizduota 13 pav., kiekvienam viršūnių skaičiui gaunama daugiau nei keturi
tūkstančiai failų, paskutinių dviejų taisyklių sugeneruoti failai priklauso nuo matricos dydžio.
23
13 pav. Eksperimentams reikalingų kainų matricų failų direktorijų struktūra
24
daryti matricai. Padidinti ar sumažinti svoriai, nors ir kelių stulpelių, gali truputį sulėtinti arba
pagreitinti algoritmo veikimą, kuris, turint pakankamai duomenų, matosi grafike.
Normalusis skirstinys
0.09
0.08
0.07
0.06
0.05
0.04
0.03
0.02
0.01
0
0 5 10 15 20 25 30 35 40 45 50
Standartinis nuokrypis
Kitas eksperimentas parodo laiką, kai poravimui naudojamas statinis Vengrų algoritmas, o
matricai pasikeitus, kad pataisyti sprendinį, poravimui iš naujo naudojamas dinaminis Vengrų
algoritmas. Gautus rezultatus matome 15 pav. Grafo briaunų svoriai vyrauja tarp 1 ir 100. Grafikas
vaizduojamas naudojant linijinę skalę, o 16 pav. matomas grafikas, kuris naudoja logaritminę
skalę. Logaritminiame atvaizdavime galime aiškiau pamatyti laiko skirtumus, kiek greičiau yra
naudoti dinaminį Vengrų algoritmą, kai pasikeičia nedidelis duomenų kiekis, bet pačių viršūnių
skaičius yra didelis.
25
Poravimo ir suporavimo iš naujo laikas (ms)
1200.00
1000.00
800.00
Laikas (ms)
600.00
400.00
200.00
0.00
64 128 256 512 1024 2048 4096
Viršūnių skaičius
100.00
Laikas (ms)
10.00
1.00
64 128 256 512 1024 2048 4096
0.10
0.01
Viršūnių skaičius
26
Iš rezultatų taip pat galima matyti, kad vis daugėjant pasikeitusių stulpelių skaičiui,
dinaminio Vengrų algoritmo laikas išauga. Žiūrint į visus duomenis gali matytis tendencija, kad
dinaminį algoritmą normaliu atveju apsimoka naudoti, kai pasikeitusių stulpelių skaičius neviršija
70% visų stulpelių.
6
5
4
3
2
1
0
0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 256
Stulpelių skaičius
17 pav. Kreivės rodo poravimą bei suporavimą iš naujo, kai vis auga besikeičiančių
stulpelių skaičius. Viršūnių skaičius 512, maksimalus svoris 10000
50.00
40.00
30.00
20.00
10.00
0.00
0 64 128 192 256 320 384 448 512 576 640 704 768 832 896 960 1024
Stulpelių skaičius
18 pav. Kreivės rodo poravimą bei suporavimą iš naujo, kai vis auga besikeičiančių
stulpelių skaičius. Viršūnių skaičius 2048, maksimalus svoris 10000
27
Taip pat turint algoritmų veikimo laikus buvo pastebėta, kad su tam tikrais svoriais
statinis algoritmas užtrunka žymiai ilgiau. Tai galime pamatyti 19 pav., kur viršūnių skaičius
1024, o maksimalūs galimi svoriai 100 ir 10000. Pagal statinio Vengrų algoritmo
implementaciją briaunų svoriai neturėtų turėti jokios reikšmės. Tai patikrinta paprasčiausiai
padalinus kainų matricą iš tam tikro svorio.
Nors atrodo, kad jeigu maksimalūs galimi svoriai grafe būtų 100 ir 10000, tai tik pradėjus
algoritmui veikti ir padalinus antrojo grafo kainų matricą iš 100 turėtume gauti tokius pačius
rezultatus, dėl to svoriai turėtų reikšmę. Tačiau padalinus laikai nepasikeičia ir pirmojo grafo
veikimo laikas išlieka žymiai ilgesnis.
Taip pat pažvelgus į algoritmo implementaciją matoma, kad kainų matrica yra double
kintamojo tipo, dėl to padalinus kainų matricą unikalių reikšmių kiekis nesumažėja (duplikatų
skaičius nepadidėja).
250.00
200.00
Laikas (ms)
150.00
100.00
50.00
0.00
0 100 200 300 400 500 600 700 800 900
Eksperimentų skaičius
19 pav. Statinio Vengrų algoritmo veikimo laikas, kai briaunų svoriai 100 bei
10000. Grafo viršūnių skaičius 1024
Norint patikrinti pastebėtus dalykus reikalingi duomenys, kurie parodytų priklausomybę nuo
grafo dydžio ir briaunų svorio duplikatų skaičiaus. Taip pat galima pažiūrėti, kuri būtent vieta
algoritme atlieka daugiau pakartojimų, kai algoritmo laikas išauga.
28
Statinio Vengrų algoritmo veikimas
100.00 30000
2500.00 250000
2000.00 200000
1500.00 150000
1000.00 100000
500.00 50000
0.00 0
10
50
100
200
300
400
500
600
700
850
1000
1200
1500
1700
2500
3500
4500
6000
8000
10000
20000
30000
40000
75000
125000
175000
Maksimalūs svoriai
29
Vengrų algoritmo "Slack" kintamųjų atnaujinimas
10000000.00
1000000.00
100000.00
10000.00
1000.00
100.00
10.00
1.00
10
50
100
200
300
400
500
600
700
850
1000
1200
1500
1700
2500
3500
4500
6000
8000
10000
20000
30000
40000
75000
125000
175000
Briaunų maksimalus svoriai
Auginantis takas
1000
Auginančio tako radimo kiekis
900
800
700
600
500
400
300
200
100
0
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51
Auginantis takas
30
Žinant šias priklausomybes galima implementuoti algoritmą, kuris turėdamas du vienodo
dydžio grafus bei pirmojo grafo sprendimą M galėtų pats parinkti, kokiu būdu greičiau galima
išspręsti priskyrimo uždavinį grafe.
3.6. Algoritmas
Algoritmo implementavimas turi būti sudarytas iš pasirinkimo, kada geriau naudoti vieną ar
kitą algoritmą. Konstruojant algoritmą turime kelis apribojimus:
• Gaunami du grafai G1 ir G2, kurie yra vienodo dydžio ir kurie gali turėti tokį patį
unikalių elementų kiekį (sutampa svoriai);
• Turime grafo G1 sprendinį.
Atsižvelgiant į prieš tai gautus rezultatus galime padaryti tokias sąlygas, pagal ką bus
renkamasi, kurį sprendimą pasirinkti, statinį ar dinaminį Vengrų algoritmą:
• Jeigu viršūnių skaičius mažiau negu 512, visuomet sprendžiame statiniu algoritmu,
nes laikas neturėtų viršyti 1 milisekundės;
• Atsižvelgiant į 22 pav. galime pasidaryti tokias taisykles, kad kai briaunų
maksimalus galimas svoris yra daugiau nei 2% bei mažesnis nei 25% grafo viršūnių
skaičiaus, visuomet sprendžiame dinaminiu Vengrų algoritmu pasitelkdami turimą
G1 grafo sprendimą;
• Jei buvusios sąlygos nepatenkintos, patikriname kiek stulpelių atnaujinta G2 grafe
palyginti su G1. Jeigu stulpelių atnaujinta daugiau negu 80%, sprendžiame
naudodami statinį Vengrų algoritmą, jeigu mažiau, naudojame dinaminį.
Implementavus tokį „Solution“ algoritmą, kuris yra paprastas, tačiau paremtas prieš tai
gautais rezultatais, veikimą galime pamatyti 24 pav. Žiūrint į duomenis pirmiausia patenkinama
sąlyga, kad veiktų dinaminis Vengrų algoritmas, o tada, pasiekus tam tikrą ribą, pradeda veikti
statinis. Patenkinus algoritmo pirmąją ar antrąją sąlygas turėti G1 algoritmo sprendinio nebūtina.
31
Poravimo ir suporavimo iš naujo (ms)
80.00
70.00
Laikas (ms) 60.00
50.00
40.00
30.00
20.00
10.00
0.00
0 64 128 192 256 320 384 448 512 576 640 704 768 832 896 960 1024
Stulpelių skaičius
Poravimas
Suporavimas iš naujo (pasikeitusių stulpelių skaičius auga)
Poravimas naudojant Solution algoritmą
24 pav. Grafo su 2048 viršūnėmis veikimo laikai, kai naudojame statinį Vengrų
algoritmą, dinaminį ir naują „Solution“ algoritmą. Maksimalus grafo svoris 10000
32
REZULTATAI IR IŠVADOS
Šiame darbe aprašyti ir palyginti du priskyrimo problemai skirti spręsti algoritmai, kurie
naudoja grafus bei jų poravimą. Vienas iš jų, tai klasikinis Vengrų algoritmas, o kitas,
dinaminis Vengrų algoritmas, kuris skirtas padidinti efektyvumą sprendžiant uždavinį, kada
keičiasi grafo briaunų svoriai.
Sukurta testavimo aplinka, kuri leido greitai generuoti didelius grafų matricų kiekius bei
atlikti pakeitimus, tokius kaip stulpelių pakeitimai. Gavus didelį duomenų kiekį buvo galima
daryti eksperimentus, kurie davė rezultatus apie algoritmų veikimo greičius bei nuo ko tai
priklauso.
Implementuoti ir ištestuoti algoritmai leido gauti rezultatus apie tai, kokiomis sąlygomis
sparčiau veikė statinis, o kada dinaminis Vengrų algoritmas. Gauti rezultatai apie tai, kaip
keičiasi algoritmo veikimo greitis, kai yra keičiamas įvairus jo stulpelių kiekis. Taip pat
matoma kaip algoritmo spartai daro įtaką unikalių svorių kiekis.
Duomenys rodo, kad nors svoriai kaip skaičiaus dydis algoritmo nepaveikia, tačiau svoris
nurodo kiek grafo matricoje gali būti unikalių elementų. Didesnis svoris leidžia grafe atsirasti
didesniam kiekiui unikalių elementų, kurie, priklausomai nuo grafo dydžio, gali daryti didelę
įtaką veikimo greičiui.
Taip pat gauti rezultatai leido sukurti algoritmą, kuris turėdamas informaciją apie grafo
dydį bei unikalių elementų kiekį gali parinkti, kada taikyti statinį, o kada dinaminį Vengrų
algoritmą. Tačiau šis parinkimas nėra universalus, prieš nustatant tam tikras ribas reikėtų atlikti
testus aplinkoje, kur būtų naudojamas toks algoritmas. Gauti rezultatai apie veikimo greitį su
tam tikru kiekiu unikalių elementų galėtų žymiai padidinti algoritmo tinkamo pasirinkimo
tikimybę.
Rezultatai leidžia teigti, kad dinaminis Vengrų algoritmas, turint gana didelį grafą, kai
viršūnių dydžiai viršija tūkstantį bei atliekamas tik kelių vienetų grafo briaunų svorių
pakeitimas, veikia ženkliai greičiau nei statinis.
Taip pat matoma vienodų elementų grafe įtaką veikimo greičiui. Kai briaunų maksimalus
svoris sveikais skaičiais viršija 10, tačiau neviršija apie trečdalį viršūnių skaičiaus, gana stipriai
suprastėja algoritmo veikimo greitis, tačiau ši įtaka bei ribos, kuomet suprastėja algoritmo
veikimo greitis taip pat priklauso ir nuo grafo dydžio.
Taigi, turint gana didelį grafą bei žinant, kad ten bus atliekamas gana mažas pakeitimų
skaičius, galima gauti pirmą optimalų poravimą naudojant statinį Vengrų algoritmą, o tada
33
pasirinkti dinaminį. Tai ženkliai padidins optimalaus sprendinio gavimą, nei kad būtų spręsti
uždavinį iš naujo naudojant statinį algoritmą.
34
ŠALTINIAI
35