【POJ】3180

来源:互联网 发布:武汉火凤凰云计算基地 编辑:程序博客网 时间:2024/06/10 01:42

http://poj.org/problem?id=3180

转自http://blog.csdn.net/qq_35546304/article/details/51870549
【问题描述】

  约翰的N只奶牛非常兴奋,因为这是个舞会之夜!他们穿上礼服和新鞋子,别上鲜花,他们要表演圆舞曲。圆舞在一个圆形的水池上进行。奶牛们围在池边站好,顺时针顺序由1到N编号。每只奶牛都面对水池,这样她就能看到其他的每只奶牛。

  为了跳这种圆舞,他们找了M条绳索。若干只奶牛的蹄子上握着绳索,绳索沿着顺时针方向绕过水池,另一端则捆在另一些奶牛的身上。这样,一些奶牛就可以牵引另一些奶牛。有的奶牛可能握有很多绳索,也有的奶牛可能一条绳索都没有。

  对于一只奶牛,比如说贝茜,她的圆舞跳的是否成功,可以这样检验:沿着她牵引的绳索,找到她牵引的奶牛,沿着这只奶牛牵引的绳索,又找到一只被牵引的奶牛,如此下去,若最终能回到贝茜,则她的圆舞跳的成功,因为这一个环上的奶牛可以逆时针牵引而跳起旋转的圆舞。如果这样的检验无法完成,那她的圆舞是不成功的。

  如果两只成功圆舞的奶牛有绳索相连接,那他们可以属于一个组合。给出每一条绳索的描述,请找出,成功跳了圆舞的奶牛有多少个组合?

【输入格式】

  第一行输入N和M,接下来的M行,每行两个整数A和B,表示A牵引着B。

【输出格式】

  成功跳圆舞奶牛组合数据。

【输入样例】

5 4
2 4
3 5
1 2
4 1

【输出样例】

1

【样例解释】

1 2 4这三只牛同属于一个成功跳了圆舞的组合,而3,5两只奶牛没有跳成功所谓圆舞.

【数据范围】

2<=N<=10000
2<=M<=50000

分析:
从此题目中可以看出这是一道经过包装之后的强连通分量题目,牵引的绳索可以看成有向图强连通分量的边,而顺逆时针可以看成是方向,圆舞的组合就是强连通分量,题目就是要求你求出强连通分量的数目,(注意要求节点数大于2),从数据范围来看,还是应采用两次DFS的方法进行解答。

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <queue>#include <vector>#include <numeric>#include <algorithm>using namespace std;int n,m;int num;bool vis[10005];int rank[10005],belong[10005];vector <int> g[10005],r[100005],vs;void dfs1(int x){   //dfs原图     vis[x]=true;    for (int i=0;i<g[x].size();i++){        int v=g[x][i];        if (!vis[v]) dfs1(v);    }    vs.push_back(x);   //按照完成时间从小到大排序 }void dfs2(int x,int num){  //dfs逆图     belong[x]=num;    rank[num]++;    for (int i=0;i<r[x].size();i++){        int v=r[x][i];        if (belong[v]==0){            dfs2(v,num);        }     }}int main(){    cin >> n >> m;    for (int i=0;i<m;i++){        int u,v;        scanf("%d%d",&u,&v);        g[u].push_back(v);        r[v].push_back(u);    }    memset(vis,false,sizeof(vis));    for (int i=1;i<=n;i++){        if (!vis[i]){            dfs1(i);        }    }    num=0;    for (int i=vs.size()-1;i>=0;i--){        int v=vs[i];        if (belong[v]==0) dfs2(v,++num);    }    int ans=0;    for (int i=1;i<=num;i++){        if (rank[i]>=2) ans++;    }    cout << ans << endl;}