題目鏈接:
http://poj.org/problem?id=2762
題目大意:
給定一個有向圖,問該圖是否連通。
有向圖連通性的定義:
對於任意兩個點u和v,總會存在一條路徑從u——v或者是從v——u。
解題思路:
如果是沒有環的有向圖的話,那麼只有當所有的點都在一條鏈上的時候,圖纔是連通的。
第1步:求取強連通分量,對有向圖進行縮點。建立新圖。
第2步:對新圖進行拓撲排序。要求每次取點的時候,度數爲0的點都只能有一個,這樣就能保證新圖是連通的。
注意事項:
在題目中用到了STL容器,對容器進行清空的時候,不要使用memset,而應該使用容器本身的清空函數,否則會出現runtime error。
源代碼:
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<string.h>
#include<string>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
vector<int> child[1001];
vector<int> pre[1001];
struct node
{
int end_time;
int id;
}s[1001];
struct node1
{
int du;
vector<int> child;
}p[1001];
bool cmp(node a,node b)
{
return a.end_time>b.end_time; //按照結束時間戳進行排序
}
int vis[1001];
int Set[1001]; //每個節點屬於哪個強連通分量
int n,m,cnt,Time,flag;
void dfs1(int now) //第1次dfs按照孩子節點進行排序得到了
{
int i,len,kid;
len=child[now].size();
for(i=0;i<len;i++)
{
kid=child[now][i];
if(!vis[kid])
{
vis[kid]=1;
dfs1(kid);
}
}
s[now].end_time=++Time;
s[now].id=now;
return;
}
void dfs2(int now)
{
int i,len,father;
len=pre[now].size();
for(i=0;i<len;i++)
{
father=pre[now][i];
if(!vis[father])
{
vis[father]=1;
dfs2(father);
}
}
Set[now]=cnt;
return;
}
void top_sort()
{
int i,j,k,t,b,len,child;
while(1) //如果每次度爲0的點只有一個,那麼這種情況就是合法的
{
b=0;
for(i=1;i<=cnt;i++)
{
if(p[i].du==0)
{
t=i;
b++;
}
}
if(b==0)
{
flag=1;
break;
}
if(b!=1) break;
p[t].du=-1;
len=p[t].child.size();
for(i=0;i<len;i++)
{
child=p[t].child[i];
p[child].du--;
}
}
return;
}
int main()
{
freopen("in.txt","r",stdin);
int cs,a,b,i,j,k,t,id,x,y,len;
scanf("%d",&cs);
while(cs--)
{
scanf("%d%d",&n,&m);
memset(s,0,sizeof(s));
for(i=0;i<=n;i++)
{
child[i].clear();
pre[i].clear();
}
while(m--)
{
scanf("%d%d",&a,&b);
child[a].push_back(b);
pre[b].push_back(a);
}
//dfs1求取時間戳
memset(vis,0,sizeof(vis));
Time=0;
for(i=1;i<=n;i++)
{
if(!vis[i])
{
vis[i]=1;
dfs1(i);
}
}
sort(s+1,s+1+n,cmp);
//dfs2求取強連通分量
memset(vis,0,sizeof(vis));
cnt=0;
for(i=1;i<=n;i++)
{
id=s[i].id;
if(!vis[id])
{
cnt++;
vis[id]=1;
dfs2(id);
}
}
//統計每個強連通分量的入度出度以及孩子與父親之類的關係
memset(p,0,sizeof(p));
for(i=1;i<=n;i++)
{
x=Set[i];
len=child[i].size();
for(j=0;j<len;j++)
{
y=child[i][j];
y=Set[y]; //y是x的孩子節點
if(x==y) continue;
p[x].child.push_back(y);
p[y].du++;
}
}
flag=0;
top_sort();
if(flag==1)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}