1. 程式人生 > >hdu1269 有向圖強連通 【Targan】(模板)

hdu1269 有向圖強連通 【Targan】(模板)

== color truct 相同 ext 結束 數據 訓練 算法

<題目鏈接>

題目大意:

為了訓練小希的方向感,Gardon建立了一座大城堡,裏面有N個房間(N<=10000)和M條通道(M<=100000),每個通道都是單向的,就是說若稱某通道連通了A房間和B房間,只說明可以通過這個通道由A房間到達B房間,但並不說明通過它可以由B房間到達A房間。Gardon需要請你寫個程序確認一下是否任意兩個房間都是相互連通的,即:對於任意的i和j,至少存在一條路徑可以從房間i到房間j,也存在一條路徑可以從房間j到房間i。

Input

輸入包含多組數據,輸入的第一行有兩個數:N和M,接下來的M行每行有兩個數a和b,表示了一條通道可以從A房間來到B房間。文件最後以兩個0結束。
Output

對於輸入的每組數據,如果任意兩個房間都是相互連接的,輸出"Yes",否則輸出"No"。
Sample Input

3 3
1 2
2 3
3 1
3 3
1 2
2 3
3 2
0 0

Sample Output

Yes
No

解題分析:
有向圖求強連通分量的裸題,下面用的是Targan算法。

#include <cstdio>
#include <cstring>

const int maxn=100000+100;

struct EDGE{
    int next;
    int to;
}edge[maxn];

int n,m,cnt,top,sumlink;
int head[maxn];
int dfn[maxn]; int vis[maxn],Stack[maxn]; int low[maxn]; int min(int a,int b){return a<b?a:b;} void add(int u,int v){ //鏈式前向星構圖 edge[++cnt].next=head[u]; edge[cnt].to=v; head[u]=cnt; } void INIT(){ //初始化 memset(dfn,0,sizeof(dfn)); memset(head,-1,sizeof(head)); memset(vis,
0,sizeof(vis)); cnt=0; //遍歷的時間坐標 top=0; //棧中的元素個數 sumlink=0; //連通分量的個數 } void Targan(int u){ if(sumlink>1)return; //如果連通分量>1,說明不符合題意,直接結束 dfn[u]=low[u]=++cnt; //dfn為遍歷的序號 Stack[++top]=u; //入棧 vis[u]=true; //標記該點在棧裏 for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(!dfn[v]){ //如果這個點沒有遍歷過 Targan(v); low[u]=min(low[u],low[v]); } else if(vis[v]){ //如果這個點在棧中 low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ //如果找到了這個連通分量的根節點 sumlink++; //連通分量數量+1 while(true){ int temp=Stack[top]; vis[temp]=0; --top; //及時將該連通塊在棧中的點排出,配合vis[]數組,能夠使同一連通塊的low值相同,而不是這個聯通塊的值等於它之前遍歷到的連通塊的low值 if(temp==u) //將該連通塊中的根節點搜索完後(根節點==該連通塊最早被dfs到的點==該連通塊在棧的最底部的點) break; } } } int main(){ while(scanf("%d %d",&n,&m)!=EOF,n|m){ INIT(); for(int i=1;i<=m;i++){ int u,v; scanf("%d %d",&u,&v); add(u,v); } for(int i=1;i<=n;i++){ if(!dfn[i]) Targan(i); } if(sumlink==1){ printf("Yes\n"); } else printf("No\n"); } return 0; }



2018-08-16

hdu1269 有向圖強連通 【Targan】(模板)