【POJ】2186

来源:互联网 发布:知乎绑定合适的话题 编辑:程序博客网 时间:2024/06/04 19:31

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

《挑战程序设计竞赛》P323
假设两头牛A和B都被其他牛认为是红人,则A认为B是,B认为A是,及存在一个包含A和B的圈,或者A和B属于同一个强连通分量。反之,如果一个牛被其他所有牛认为是红人,那么其所在的强连通分量的所有牛都被其他所有牛认为是红人,显然这样的强连通分量最多只有一个,否则强连通分量还能继续扩大,不满足强连通分量的定义。我们把图进行强连通分量分解后,可以得到各个强连通分量的拓扑排序后的顺序,显然能够成为解的只有可能是拓扑序最后的强连通分量,只需判断这个强连通分量能否从其他任意点到达即可。时间复杂度为O(N+M)。

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <queue>#include <stack>#include <vector>#include <numeric>#include <algorithm>using namespace std;const int maxn=10005;const int maxm=50005;int n,m;vector <int> G[maxm];//图的邻接表表示vector <int> rG[maxm];//反向vector <int> vs;//后序遍历的顶点列表 bool vis[maxn];int cmp[maxn];//所属强联通分量的拓扑排序void add(int from,int to){    G[from].push_back(to);    rG[to].push_back(from);}void dfs(int v){    vis[v]=true;    for (int i=0;i<G[v].size();i++){        if (!vis[G[v][i]]){            dfs(G[v][i]);        }    }    vs.push_back(v);}void rdfs(int v,int k){    vis[v]=true;    cmp[v]=k;    for (int i=0;i<rG[v].size();i++){        if (!vis[rG[v][i]]){            rdfs(rG[v][i],k);        }    }}int scc(){    memset(vis,0,sizeof(vis));    vs.clear();    for (int i=1;i<=n;i++){        if (!vis[i]){            dfs(i);        }    }    memset(vis,0,sizeof(vis));    int k=0;    for (int i=vs.size()-1;i>=0;i--){        if (!vis[vs[i]]) rdfs(vs[i],k++);    }    return k;}int main(){    cin >> n >> m;    for (int i=0;i<m;i++){        int from,to;         cin >> from >> to;        add(from,to);    }    //统计备选解的个数     int Scc=scc();    int u=0,num=0;    for (int i=1;i<=n;i++){         if (cmp[i]==Scc-1){            u=i;            num++;        }    }    //检查是否又从所有点可达     memset(vis,0,sizeof(vis));    rdfs(u,0);    for (int i=1;i<=n;i++){        if (!vis[i]){            num=0;            break;        }    }    cout << num << endl;}