Poj2762——有向圖縮點+拓撲排序

題目鏈接:

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章