Trajan演算法(強連通+縮點)
http://poj.org/problem?id=1236
問題概述:n所學校,它們通過單向邊連線,如果A-->B表示A學校可以傳遞資訊給B學校,那麼問題來了,一:至少
要向幾個學校傳遞資訊,才能保證所有學校都能收到資訊;二:至少要新增多少組關係,才能保證給任意一個學校
原始資訊後,其他所有學校都能收到資訊,輸入第一個數表示有多少學校,後面n行,第i行第k個數表示i-->k(每行
輸入到0結束)(POJ1236)
輸入樣例: 對應輸出:
5 1
2 4 3 0 2
4 5 0
0
0
1 0
兩個頂點強連通:有向圖G中,兩個頂點可以通過某些路徑互相到達
強連通圖:該有向圖中的任意兩個頂點都強連通
強連通分量:非強連通有向圖中的極大強連通子圖(注意不是最大)
定理:
①當一個點既是強連通子圖Ⅰ中的點,又是強連通子圖Ⅱ中的點,則它是強連通子圖Ⅰ∪Ⅱ中的點
②強連通分量一定由若干個環組成的
③在任何深度優先搜尋中,同一強連通分量內的所有頂點均在同一棵深度優先搜尋樹中,也就是說,強連通分量一
定是有向圖的某個深搜樹子樹
Trajan主要原理:
time[k]:第一次遍歷到k點的時間
low[k]:k點所在強連通分量子圖中第一個被搜到的點的time值
vis[k]:k點是否已經遍歷
棧:每當搜尋到一個點時,將它壓入棧,當這個點k所有子樹全部搜尋完畢時,如果low[k]==time[k],說明已經找到
了一個強連通分量,將k以及在k之上的元素彈全部出棧(它們全部屬於一個強連通分量,且這個強連通分量不含其
它點)
搜尋過程:
→當點k有與點c相連,如果此時(time[k]時)c不在棧中,搜尋c點,當c點及其子樹搜尋完畢回溯後,計算出
low[k] = min(low[k], low[c])
→當點k有與點c相連,如果此時(time[k]時)c在棧中,low[k] = min(low[k], time[c])
→搜尋完畢後,棧內應該沒有點了
期間保證:每個點每條邊都只被搜尋1次,且必須搜尋1次,複雜度n+m,如果遍歷完整個搜尋樹後某個點的time值
等於low值,則它是該搜尋子樹的根,這時,它以上(包括它自己)一直到棧頂的所有元素組成一個強連通分量,但
屬於該強連通分量的所有的點low值不一定一致(但只有根節點滿足low值與time值相等)
縮點過程:
→本質:將一個聯通塊作為一個點ltt[k]:k點屬於第ltt[k]個聯通塊
→遍歷一遍所有的邊,如果邊(u,v)中u和v屬於不同聯通塊,則將它們兩個所在的聯通塊連線在一起
題解:
設ain為縮點之後入度為0的點的個數,aout為縮點之後出度為0的點的個數,顯然:這題第一個答案就是ain,第二
個答案當全圖強連通時答案為0,否則為max(ain, aout)
#include<stdio.h>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
vector<int> v[105], nv[105];
stack<int> st;
int n, t, vis[105], inst[105], low[105], time[105], ltt[105], num, ain, aout, in[105], out[105];
void Trajan(int x);
int main(void)
{
int i, j, x, temp;
scanf("%d", &n);
for(i=1;i<=n;i++)
{
while(scanf("%d", &x), x!=0)
v[i].push_back(x);
}
t = num = 0;
for(i=1;i<=n;i++)
{
if(vis[i]==0)
Trajan(i);
}
for(i=1;i<=n;i++)
{
for(j=0;j<v[i].size();j++)
{
temp = v[i][j];
if(ltt[i]!=ltt[temp])
nv[ltt[i]].push_back(ltt[temp]);
}
}
for(i=1;i<=num;i++)
{
for(j=0;j<nv[i].size();j++)
in[nv[i][j]]++, out[i]++;
}
ain = aout = 0;
for(i=1;i<=num;i++)
{
if(in[i]==0)
ain++;
if(out[i]==0)
aout++;
}
printf("%d\n", ain);
if(num==1)
printf("0\n");
else
printf("%d\n", max(ain, aout));
return 0;
}
void Trajan(int x)
{
int i, temp;
st.push(x);
inst[x] = vis[x] = 1;
low[x] = time[x] = ++t;
for(i=0;i<v[x].size();i++)
{
temp = v[x][i];
if(vis[temp]==0)
{
Trajan(temp);
low[x] = min(low[x], low[temp]);
}
else if(inst[temp]==1)
low[x] = min(low[x], time[temp]);
}
if(low[x]==time[x])
{
num++;
while(st.empty()==0)
{
temp = st.top();
st.pop();
ltt[temp] = num;
inst[temp] = 0;
if(temp==x)
break;
}
}
}
相關文章
- HDU 2767 Proving Equivalences Tarjan 強連通縮點UI
- 【演算法學習】tarjan 強連通、點雙、邊雙及其縮點 重磅來襲!!!!演算法
- 強連通------tarjan演算法詳解及與縮點聯合運用演算法
- 演算法學習之路|強連通分量+縮點演算法
- 強連通分量及縮點tarjan演算法解析演算法
- 圖之強連通、強連通圖、強連通分量 Tarjan演算法演算法
- 強連通分量及縮點 演算法解析及例題演算法
- 【模板】tarjan 強連通分量縮點
- POJ 2186 Popular Cows(強連通分量縮點,Tarjan演算法)演算法
- 強連通圖的演算法演算法
- 圖論複習之強連通分量以及縮點—Tarjan演算法圖論演算法
- 強連通分量與縮點(Tarjan演算法)(洛谷P3387)演算法
- HDU2767Proving Equivalences[強連通分量 縮點]UI
- 強連通演算法--Tarjan個人理解+詳解演算法
- Tarjan演算法_縮點演算法
- 抓間諜(強連通)
- 有向圖的連通性(判強連通)
- tarjan演算法求scc & 縮點演算法
- 強連通分量(Tarjan演算法)演算法
- 連通圖與Tarjan演算法演算法
- Tarjan演算法(強連通分量分解)演算法
- 圖論——強連通分量(Tarjan演算法)圖論演算法
- 4連通域邊界填充演算法和8連通域邊界填充演算法C++演算法C++
- Tarjan演算法求強連通分量總結演算法
- 強連通分量-tarjan演算法模板詳解演算法
- 一個強大的圖片壓縮演算法—近微信壓縮機制的Luban演算法
- 縮點
- kosaraju 和 tarjan演算法詳解(強連通分量)演算法
- 【筆記】tarjian演算法 求強連通分量筆記演算法
- Tarjan演算法三大應用之強連通分量演算法
- 連通圖演算法詳解之① :Tarjan 和 Kosaraju 演算法演算法
- SCC縮點
- 計算機演算法:資料壓縮之點陣圖(2)計算機演算法
- 【Algorithm】連結串列演算法中啞結點作用Go演算法
- 強連通分量
- 尋找圖的強連通分量:tarjan演算法簡單理解演算法
- 檔案壓縮增強工具-pgzip
- ifix5.8連線ab plc的點-通過igs