Poj2762——有向图缩点+拓扑排序

来源:互联网 发布:帝国cms广告代码 编辑:程序博客网 时间:2024/05/18 03:02

题目链接:

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;}

原创粉丝点击