poj2186

来源:互联网 发布:手机淘宝充值怎么退款 编辑:程序博客网 时间:2024/04/30 13:39

链接:点击打开链接

题意:给定N头牛的牛群和M个有序对(A,B),(A,B)表示牛A认为牛B是红人,并且该关系具有传递性,例如(A,B),(B,C)则(A,C),求被其他所有牛认为是红人的牛的总数

代码:

#include <vector>#include <cstdio>#include <cstring>#include <stdlib.h>#include <iostream>#include <algorithm>using namespace std;int V;                              //定点数vector<int> G[10005];               //正向建图vector<int> rG[10005];              //反向建图vector<int> vs;                     //遍历的顺序bool used[10005];int cmp[10005];                     //强连通分量的拓扑序void add_edge(int from,int to){    G[from].push_back(to);    rG[to].push_back(from);}void dfs(int v){    int i;    used[v]=1;    for(i=0;i<G[v].size();i++)    if(!used[G[v][i]])    dfs(G[v][i]);    vs.push_back(v);}void rdfs(int v,int k){    int i;    used[v]=1;    cmp[v]=k;    for(i=0;i<rG[v].size();i++)     //只有强连通分量才不受反向建边    if(!used[rG[v][i]])             //的影响,因此找出强连通分量的    rdfs(rG[v][i],k);               //同时,找出强连通分量的拓扑序}int scc(){    int i,k;    memset(used,0,sizeof(used));    vs.clear();    for(i=0;i<V;i++)    if(!used[i])    dfs(i);    memset(used,0,sizeof(used));    k=0;    for(i=vs.size()-1;i>=0;i--)     //拓扑序最小的点在容器vs的最后面    if(!used[vs[i]])    rdfs(vs[i],k++);    return k;}                                   //强连通分量模板int main(){    int n,m,i,j,x,y,u,num;    while(scanf("%d%d",&V,&m)!=EOF){        for(i=0;i<m;i++){            scanf("%d%d",&x,&y);            add_edge(x-1,y-1);        }        n=scc();                    //强连通分量的个数也就是拓扑序的//        cout<<n<<endl;            //最大值        u=num=0;        for(i=0;i<V;i++)        if(cmp[i]==n-1){            //只有拓扑序最大的强连通分量中的            u=i;                    //点才是备选解            num++;        }        memset(used,0,sizeof(used));        rdfs(u,0);        for(i=0;i<V;i++)        if(!used[i]){               //用反向的rdfs看是否能到达所有点            num=0;            break;        }        printf("%d\n",num);    }    return 0;}


0 0
原创粉丝点击