TARJAN演算法與其運用
阿新 • • 發佈:2018-11-06
一.割點與割邊
題目連結 http://hihocoder.com/problemset/problem/1183
割點:
- x不是根:只要有low[v[x]]>=low[x] 說明v[x]不通過x沒法回到x來時的地方,所以x為割點
- x是根:x有兩個及以上的直接兒子(注意這裡的兒子是放在!dfn中的,不然就是x的兒子的兒子)即可
程式碼如下:注意點都寫註釋裡了呀!
void tarjan(int x,int fa) { dfn[x]=low[x]=++iindex;int child=0,flag=0; for(int i=0;i<v[x].size();i++) { if(!dfn[v[x][i]]) { child++;//注意child的位置! tarjan(v[x][i],x); low[x]=min(low[x],low[v[x][i]]); if(low[v[x][i]]>=dfn[x]) flag=1;//割點條件 } else if(v[x][i]!=fa) low[x]=min(low[x],dfn[v[x][i]]);//這裡要判斷v[x][i]不是x的父親哦 } if(x==root&&child>=2) cut[x]=1; if(x!=root&&flag) cut[x]=1; if(cut[x]) tot++; }
割邊:
- 與割點的區別:如果v[x]連爸爸都找不到了,那他到爸爸的那條邊就是連線他們的唯一路徑,就是橋(割邊)
所以這裡改成:low[v[x]]>dfn[x]
別的都一樣啊,不過不用判根
void tarjan2(int x,int fa) { dfn[x]=low[x]=++iindex; for(int i=0;i<v[x].size();i++) { if(!dfn[v[x][i]]) { tarjan2(v[x][i],x); low[x]=min(low[x],low[v[x][i]]); if(low[v[x][i]]>dfn[x]) { int t1=min(v[x][i],x);int t2=max(v[x][i],x); ans.push_back(make_pair(t1,t2)); } } else if(v[x][i]!=fa) low[x]=min(low[x],dfn[v[x][i]]); } }
二.邊雙
題目連結 http://hihocoder.com/problemset/problem/1184
1.就是做一遍和剛才求割點差不多的程式,但為了存點,我們引入了stack
2.stack中到x的點都屬於一個聯通分量
程式碼如下:
void tarjan(int x,int fa) { dfn[x]=low[x]=++iindex;s.push(x);vis[x]=1; for(int i=0;i<v[x].size();i++) { if(!dfn[v[x][i]]) { tarjan(v[x][i],x); low[x]=min(low[x],low[v[x][i]]); } else if(v[x][i]!=fa) low[x]=min(low[x],dfn[v[x][i]]); } if(low[x]==dfn[x]) { tot++;int minv=1e9; while(1) { int tmp=s.top();minv=min(minv,tmp); belong[tmp]=tot; s.pop(); if(tmp==x) break; } num[tot]=minv; } }
三.強聯通分量
http://hihocoder.com/problemset/problem/1185
1.與邊雙的思路很像,但它是有向圖
2.所以引入vis的陣列以判斷這個點在不在stack裡。(而邊雙只是判斷他是不是father)
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++iindex;vis[x]=1;s.push(x);
for(int i=0;i<v[x].size();i++)
{
if(!dfn[v[x][i]])
{
tarjan(v[x][i],x);
low[x]=min(low[x],low[v[x][i]]);
}
else if(vis[v[x][i]])//這裡和邊雙不一樣
{
low[x]=min(dfn[v[x][i]],low[x]);
}
}
if(dfn[x]==low[x])
{
while(1)
{
int tmp=s.top();s.pop();
vis[tmp]=0;if(tmp!=x) w[x]+=w[tmp];
belong[tmp]=x;
if(tmp==x) break;
}
}
}
應用
1.縮點:https://www.luogu.org/problemnew/show/P3387
強聯通分量的基本應用 本質:有向有環圖->有向無環圖DAG
2.搶掠計劃:https://www.luogu.org/problemnew/show/P3627
求最長路徑,一個基本應用吶
注意topo和dfs的應用
有出發點用dfs,否則的用topo
3.資訊傳遞:https://www.luogu.org/problemnew/show/P2661
求最小環,用的強聯通分量。不過這個用dfs更清晰簡單 vis:0,1,2