Witam,
Na podstawie informacji zawartych w Wprowadzenie do algorytmów Cormena i materiałów z sieci napisałem algorytm Edmondsa-Karpa do wyznaczania największego możliwego przepływu w sieci (macierz sąsiedztwa, przeszukiwanie wszerz). Niestety nie działa. Debbuger w VS2012 pokazuje, ze program nie wychodzi z pętli:
while (i != source)
{
v1 = father[i];
flow[v1][i] = flow[v1][i] + flow_path[outlet];
flow[i][v1] = flow[i][v1] - flow_path[outlet];
i = v1;
}
Jak rozumiem wynika to z tego, że w pewnym momencie dochodzi do sytuacji, w której wierzchołek 'a' jest poprzednikiem 'b' i odwrotnie. Od dłuższego czasu nie mogę poradzić sobie z tym problemem, proszę o pomoc.
ps. Ujście jest "na sztywno" ustawione na 6 ponieważ testuje algorytm na grafie, którego ujściem jest właśnie wierzchołek 6.
ps2. MAX_INT to maksymalna wartość int z biblioteki <limits>.
Cały kod algorytmu:
void FordFulkerson::doFordFulkerson(bool print_console)
{
// Plik do zapisu
ofstream file;
// Zmienna do mierzenia czasu
Timer timer;
// Zrodlo
int source = graph->getStartVertex();
// Ujscie
int outlet = 6;
// Maksymalny przeplyw poczatkowo ustawiony na zero
int flow_max = 0;
// Macierz przeplywow w krawedzich
int **flow = new int*[graph->getVerticesCount()];
for (int i = 0; i < graph->getVerticesCount(); i++)
{
flow[i] = new int[graph->getVerticesCount()];
}
// Ustawiam wartosci przeplywow w macierzy przeplywow na zero
for (int i = 0; i < graph->getVerticesCount(); i++)
{
for (int j = 0; j < graph->getVerticesCount(); j++)
{
flow[i][j] = 0;
}
}
// Tablica, w ktora wpisuje poprzednika - 'ojca' danego wierzcholka
int *father = new int[graph->getVerticesCount()];
// Tablica, w ktorej przechowuje przepustowosc sciezek
int *flow_path = new int[graph->getVerticesCount()];
// Kolejka
list <int> queue;
// Pomocnicze
int escape = 0; // do wychodzenia z zagniezdzonych petli
int v1 = 0; // wierzcholek 1
int current_flow = 0; // przechowuje tymczasowy, aktualny przeplyw
/*********************************************************
** Wlasciwy algorytm Forda-Fulkersona (Edmondsa-Karpa) **
*********************************************************/
// Rozpoczęcie pomiaru czasu wykonywania
timer.startTimer();
do
{
// Zeruje tablice poprzednikow
for (int i = 0; i < graph->getVerticesCount(); i++)
{
father[i] = 0;
}
// Ustawiam poprzednik zrodla na -1, poniewaz zrodlo nie ma poprzednika
father[source] = -1;
// Przeplyw przez zrodlo ustawiam na nieskonczony
flow_path[source] = MAX_INT;
// Zeruje kolejke
queue.clear();
// Dodaje zrodlo do kolejki
queue.push_back(source);
// Zeruje escape
escape = 0;
while (queue.size())
{
// Wpisuje do v1 pierwszy element z kolejki,
// a nastepnie go usuwam
v1 = queue.front();
queue.pop_front();
// Sprawdzam sasiadow wierzcholka v1,
// przegladam matrix[v1][]
for (int i = 0; i < graph->getVerticesCount(); i++)
{
// Wyznaczam przepustowosc residualna dla krawedzi v1->i,
// jesli takiej krawedzi nie ma w liscie sasiedztwa,
// otrzymam zero (brak krawedzi w matrix oznaczony jest przez zero)
current_flow = graph->matrix[v1][i] - flow[v1][i];
// Sprawdzam czy krawedz istnieje i czy byla juz wybrana,
// przez metode Forda - Fulkersona
if (current_flow && !father[i])
{
father[i] = v1;
// Dla wierzcholka 'i' obliczam przepustowosc residualna - jest to mniejsza wartosc z przepustowosci
// sciezki dla poprzednika 'v1' i biezacej przepustowosci residualnej krawedzi v1->i
if (flow_path[v1] > current_flow)
{
flow_path[i] = current_flow;
}
else
{
flow_path[i] = flow_path[v1];
}
// Jesli osiagnalem ujscie
if (i == outlet)
{
// Zwiekszam maksymalny przeplyw sieci
// o przepustowosc residualna sciezki
flow_max = flow_max + flow_path[outlet];
// Cofam sie wstecz po sciezce, zwiekszam przeplywy wzdluz jej kierunku
// i zmniejszam w kierunku przeciwnym
while (i != source)
{
v1 = father[i];
flow[v1][i] = flow[v1][i] + flow_path[outlet];
flow[i][v1] = flow[i][v1] - flow_path[outlet];
i = v1;
}
// Ustawienie escape sluzy do wyjscia z zagniezdzonych petli
escape = 1;
break;
}
// Jesli 'i' nie jest ujsciem 'outlet' to dadaje do kolejki
queue.push_back(i);
}
}
// Wyjscie z petli while(queue.size()), jesli znaleziono sciezke
if (escape)
{
break;
}
}
// Wyjscie z petli do..while(true), jesli nie znaleziono sciezki
if (!escape)
{
break;
}
} while(true);
// Zakonczenie pomiaru
timer.stopTimer();
// Zapisanie czasu wykonania do zmiennej skladowej klasy
this->setFordFulkersonTime(timer);
// Wyswietlenie wyniku na konsoli, jesli wlaczone
if (print_console)
{
cout << endl << "Wyznaczony przeplyw sieci:" << endl;
cout << "Zrodlo: " << graph->getStartVertex()
<< " Ujscie: " << outlet << " Przeplyw max: " << flow_max << endl << endl;
cout << endl << endl;
cout << "Czas wykonania: " << setprecision(15) << getFordFulkersonTime().getDuration() << " ms" << endl << endl << endl;
}
// Zapisanie wyniku do pliku
file.open("Results/fordfulkerson.txt", ios::app);
for(int i = 0; i < graph->getVerticesCount(); i++)
{
for(int j = 0; j < graph->getVerticesCount(); j++)
{
if(graph->matrix[i][j])
{
cout << i << " -> " << j << " "
<< flow[i][j] << "/" << graph->matrix[i][j] << endl;
}
}
}
// Czyszczenie pamieci
delete [] flow_path;
delete [] father;
for (int i = 0; i < graph->getVerticesCount(); i++)
{
delete [] flow[i];
}
delete [] flow;
}