Tarjan演算法求強連通分量總結
Tarjan演算法求強連通分量總結
首先明確強連通分量的概念:如果圖中的任意兩個點都能互相到達,則為強連通分量。極大強連通分量:不被其它任何強連通分量包含的強連通分量。
強連通分量主要與兩種邊有關:交叉邊和後向邊。
交叉邊是兩個無關係的點之間所構成的,而後向邊是根節點的子節點指向根結點的一種邊
Tarjan演算法原理:
-
建立low陣列(用於記錄該點所在的連通子圖的根節點的搜尋子樹所遍歷的時間)與dfn陣列(記錄當前點遍歷的時間)Index:記錄搜尋過程所進行的時間
-
初始化dfn、index,當前點u的初始值為時間
-
u入棧並標記
-
遍歷與u相連的所有點(記為v)
-
如果v未被遍歷,遞迴遍歷v點,然後更新low[u] low[u]=min(low[u],low[v]);
-
如果 v已經被遍歷且在棧中直接更新low[u]
low[u]=min(low[u],dfn[v]);
-
判斷low[u]==low[v]如果成立,將包括u在內的所有點出棧並記錄,則求得強連通分量之一
-
繼續遍歷,直至結束
-
注意:在一個圖中,起點不唯一,所以tarjan演算法應該遍歷所有未被遍歷的點(vis[i]==0)
本演算法主要應用範圍是對複雜的有向圖的縮點優化。如果某些點構成一個環,完全可以把它們看作一個點,加快程式執行效率
Question:如果是有向有權圖使用縮點時應該怎麼處理權值的問題?
FZOJ1638求強連通分量
描述
輸入一個圖,輸出該圖中的最大強連通分量。
輸入
第一行:n和m(n<=10000,m<=100000,n為節點個數,m為邊的條數)
接下來m行,每行兩個數:a,b,表示a指向b的邊(a,b為非負整數);
輸出
輸出最大強連通分量的節點,按照節點編號從小到大輸出,如果有多個強連通分量節點數相同,則輸出節點編號字典序較小的。
樣例輸入
6 8
1 3
3 5
5 6
1 2
4 1
2 4
4 6
3 4
樣例輸出
1 2 3 4
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int first[10020],nxt[100200],go[100200],arcnum=1;
int dfn[10020],low[10020],stack[100200],top,dex,vis[10020];
int rt,ans[10020],temp[10020],sum;
void addarc(int a,int b){
nxt[arcnum]=first[a];
first[a]=arcnum;
go[arcnum++]=b;
}
void tarjan(int u){
dfn[u]=low[u]=++dex;
stack[++top]=u; vis[u]=1;
for(int p=first[u];p!=0;p=nxt[p]){
int v=go[p];
if(vis[v]==0){
vis[v]=1;
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]==1)
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
int v; sum=0;
do{
v=stack[top--];
vis[v]=2;
temp[++sum]=v;
}while(u!=v);
if(rt<sum){
rt=sum;
for(int i=1;i<=sum;i++)
ans[i]=temp[i];
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
int n,m,a,b;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
addarc(a,b);
}
for(int i=0;i<=n-1;i++)
if(vis[i]==0){
top=0;dex=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
stack[++top]=i;
tarjan(i);
}
sort(ans+1,ans+1+rt);
for(int i=1;i<=rt;i++)
printf("%d ",ans[i]);
return 0;
}
Poj2186Popular Cows
Description
Every cow's dream is to become the mostpopular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you aregiven up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) thattell you that cow A thinks that cow B is popular. Since popularity is transitive,if A thinks B is popular and B thinks C is popular, then A will also think thatC is
popular, even if this is not explicitlyspecified by an ordered pair in the input. Your task is to compute the numberof cows that are considered popular by every other cow.
Input
* Line 1: Two space-separated integers, Nand M
* Lines 2..1+M: Two space-separated numbersA and B, meaning that A thinks B is popular.
Output
output
* Line 1: A single integer that is thenumber of cows who are considered popular by every other cow.
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
Hint
Cow 3 is the only cow of high popularity.
題目大意
N頭奶牛(N≤10000)
M對關係(a , b),表示a認為b是受歡迎的
關係具有傳遞性,即若(a,b),(b,c)→(a,c)
詢問有多少頭奶牛是被其他所有奶牛認為是受歡迎的
這道題據說不使用強連通演算法優化也能做出來,就是說tarjan演算法只是進行優化。
進過分析可以發現,在有向無環圖DAG圖中,要想一頭(群)牛被其它所有牛歡迎,必須滿足只有它自己的出度為0,其它的牛所構成的圈子(環)的出度必須大於零才可以
這樣就得到了解決方法,用tarjan演算法算出所有的強連通分量並將它們合併成一個點,再做一次搜尋,如果這個環對外的出度為0則其中所有牛對其他牛的出度都為0
如果一個DAG圖有兩個以上出度為0得點,那麼總有一個點無法到達其它任意一個點
遍歷所有環與點,如果出度為0的只有一個則輸出答案,否則答案為0
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10000+200,MAXM=50000+200;
int first[MAXN],nxt[MAXM],go[MAXM],arcnum=1;
int dfn[MAXN],low[MAXN],stack[MAXM],top;
int scc[MAXN],idx,cscc,vis[MAXN];//記錄強連通分量
int cd[MAXN],cd_scc[MAXN];
void addarc(int a,int b){
nxt[arcnum]=first[a];
first[a]=arcnum;
go[arcnum++]=b;
cd[a]++;
}
void tarjan(int u){
low[u]=dfn[u]=++idx;
stack[++top]=u; vis[u]=1;
for(int p=first[u];p!=0;p=nxt[p]){
int v=go[p];
if(vis[v]==0){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(vis[v]==1)
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
int v;
cscc++;
do{
v=stack[top--];
vis[v]=2;
scc[v]=cscc;
}while(u!=v);
}
}
int main()
{
// freopen("in.txt","r",stdin);
int n,m,a,b;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
addarc(a,b);
}
for(int i=1;i<=n;i++)
if(vis[i]==0)
tarjan(i);
if(idx<n){
printf("0");
return 0;
}
for(int u=1;u<=n;u++)
for(int p=first[u];p!=0;p=nxt[p]){
int v=go[p];
if(scc[u]!=scc[v])
cd_scc[scc[u]]++;
}
int c1=0;
for(int i=1;i<=cscc;i++){
if(cd_scc[i]==0&&c1==0)
c1=i;
else if(c1!=0&&cd_scc[i]==0){
printf("0");
return 0;
}
}
int ans=0;
for(int i=1;i<=n;i++)
if(scc[i]==c1)
ans++;
printf("%d",ans);
return 0;
}
相關文章
- 圖之強連通、強連通圖、強連通分量 Tarjan演算法演算法
- 強連通分量(Tarjan演算法)演算法
- Tarjan演算法(強連通分量分解)演算法
- Tarjan 求有向圖的強連通分量
- 圖論——強連通分量(Tarjan演算法)圖論演算法
- 強連通分量-tarjan演算法模板詳解演算法
- kosaraju 和 tarjan演算法詳解(強連通分量)演算法
- Tarjan演算法三大應用之強連通分量演算法
- 強連通分量及縮點tarjan演算法解析演算法
- 【模板】tarjan 強連通分量縮點
- 尋找圖的強連通分量:tarjan演算法簡單理解演算法
- POJ 2186 Popular Cows(強連通分量縮點,Tarjan演算法)演算法
- 20行程式碼實現,使用Tarjan演算法求解強連通分量行程演算法
- 圖論複習之強連通分量以及縮點—Tarjan演算法圖論演算法
- 【筆記】tarjian演算法 求強連通分量筆記演算法
- 強連通演算法--Tarjan個人理解+詳解演算法
- 強連通分量與縮點(Tarjan演算法)(洛谷P3387)演算法
- 連通圖與Tarjan演算法演算法
- 強連通分量
- HDU 2767 Proving Equivalences Tarjan 強連通縮點UI
- 求有向圖的強連通分量(c語言版)C語言
- 強連通------tarjan演算法詳解及與縮點聯合運用演算法
- 演算法學習之路|強連通分量+縮點演算法
- 連通圖演算法詳解之① :Tarjan 和 Kosaraju 演算法演算法
- 強連通分量及縮點 演算法解析及例題演算法
- tarjan演算法求scc & 縮點演算法
- 強連通圖的演算法演算法
- Trajan演算法(強連通+縮點)演算法
- HDU2767Proving Equivalences[強連通分量 縮點]UI
- 影像增強演算法總結演算法
- POJ 1523 SPF (無向圖求割點 tarjan演算法)演算法
- 演算法面試通關40講總結演算法面試
- Tarjan演算法及其應用 總結+詳細講解+詳細程式碼註釋演算法
- 演算法問題總結-連結串列相關演算法
- Tarjan演算法_縮點演算法
- 抓間諜(強連通)
- 邊分治維護強連通分量(CF1989F,P5163)
- tarjan—演算法的神(一)演算法