圖的DFS算法對於每一個圖節點u有2個重要的時間d[u]和f[u],分別代表找到u的時間(其變爲灰色節點的時間)以及u完成的時間(其變爲黑色節點的時間).
f[u]越大可能其在最上面(樹根處),所以要等其所有子孫都完成其才能完成.
1、拓撲排序
對於一個圖,找拓撲排序的方法就是通過按照完成時間f[u]的遞減順序即爲一個拓撲排序:
void graph::topology(int start,queue<int> &tpmap)
{
int Pnum = this->Pnum;
int visit[1000];
memset(visit, 0, sizeof(visit));
stack<int> s;
loop: s.push(start);
visit[start] = 1;
int step;
int h = 0;
while (!s.empty())
{
int find = 0;
int p = s.top();
for (int i = 0; i < Pnum; i++)
{
if (!visit[i] && edge[p][i] != INF)
{
find = 1;
s.push(i);
visit[i] = 1;
h++;
}
}
if (!find)
{
int temp = s.top();
s.pop();
tpmap.push(temp);
h--;
}
}
for (int i = 0; i < Pnum; i++)
if (!visit[i])
{
start = i;
goto loop;
}
for (int i = 0; i < Pnum; i++)//將隊列元素顛倒
{
s.push(tpmap.front());
tpmap.pop();
}
for (int i = 0; i < Pnum; i++)
{
tpmap.push(s.top());
s.pop();
}
}
2、Kosaraju算法
此法用了2此DFS,第一次在原圖,第二次在其轉置圖,此算法主要利用下面定理:
原圖的DFS完成時間晚的連通分量,其在轉置圖中不會有邊指向在原圖DFS時完成時間早的連通分量.
算法:
step1:對原圖G進行深度優先遍歷,記錄每個節點的離開時間。
step2:選擇具有最晚離開時間的頂點,對反圖GT進行遍歷,刪除能夠遍歷到的頂點,這些頂點構成一個強連通分量。
step3:如果還有頂點沒有刪除,繼續step2,否則算法結束。
void graph::strongly_connected_conponets(int start)
{
queue<int> tpmap;
topology(start, tpmap);//step1
graph reverse_g;
for (int i = 0; i < Pnum; i++)//step2、構造圖G的轉置圖
for (int j = 0; j < Pnum; j++)
{
if (edge[i][j])
reverse_g.edge[j][i] = edge[i][j];
}
int visit[100];
memset(visit, 0, sizeof(visit));
stack<int> s;
while (!tpmap.empty())//step3
{
if (!visit[tpmap.front()])
{
s.push(tpmap.front());
visit[tpmap.front()] = 1;
tpmap.pop();
}
else
{
tpmap.pop();
continue;
}
while (!s.empty())//每棵樹都完成了即爲一個連通分量
{
int find = 0;
int now_point = s.top();
for (int i = 0; i < Pnum; i++)
{
if (reverse_g.edge[now_point][i] != INF && !visit[i])
{
find = 1;
s.push(i);
visit[i] = 1;
}
}
if (!find)
{
cout << now_point;
s.pop();
}
}
cout << endl;
}
}