BZOJ1051: [HAOI2006]受欢迎的牛(强连通Tarjan 缩点)

来源:互联网 发布:淘宝设置第二件半价 编辑:程序博客网 时间:2024/05/18 11:20

题目链接
题意:每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
解法:跑一遍Tarjan算法,进行缩点,然后在缩点后的图上找出度为0 的个数。

#include<bits/stdc++.h>using namespace std;#define LL long long#define pb push_back#define X first#define Y second#define cl(a,b) memset(a,b,sizeof(a))typedef pair<int,int> P;const int maxn=50005;const int inf=1<<27;void f(char*a,char*b){    freopen(a,"r",stdin);    freopen(b,"w",stdout);}vector<int> G[maxn];int tim,top,cnt;bool ins[maxn];int dfn[maxn],low[maxn],s[maxn],belong[maxn];int num[maxn];void dfs(int u){    dfn[u]=low[u]=++tim;    s[++top]=u;    ins[u]=true;    for(int i=0;i<G[u].size();i++){        int v=G[u][i];        if(!dfn[v]){            dfs(v);            low[u]=min(low[u],low[v]);        }else if(ins[v]&&dfn[v]<low[u]){            low[u]=dfn[v];        }    }    if(low[u]==dfn[u]){        cnt++;        int v;        do{            v=s[top--];            ins[v]=false;            belong[v]=cnt;            num[cnt]++;        }while(v!=u);    }}void Tarjan(int n){    cnt=tim=top=0;    cl(dfn,0);    cl(belong,0);    cl(ins,false);    cl(num,0);    for(int i=1;i<=n;i++)if(!dfn[i]){dfs(i);}}struct Edge{    int x,y;}p[maxn];int outdeg[maxn];int main(){    int n,m;    while(~scanf("%d%d",&n,&m)){    for(int i=0;i<maxn;i++)G[i].clear();        for(int i=0;i<m;i++){            int x,y;            scanf("%d%d",&x,&y);            p[i].x=x;p[i].y=y;            G[x].pb(y);        }        Tarjan(n);        cl(outdeg,0);        for(int i=0;i<m;i++){            if(belong[p[i].x]!=belong[p[i].y]){                outdeg[belong[p[i].x]]++;            }        }        int ans=0,sum__=0;        for(int i=1;i<=cnt;i++)if(outdeg[i]==0){            ans+=num[i];sum__++;        }        if(sum__>=2){printf("0\n");continue;}//题目没有这个,但是明显出度为0 多余2的是无解的        printf("%d\n",ans);    }    return 0;}
0 0