Popular Cows - 2186 (tarjan 缩点)

Popular Cows

  OpenJ_Bailian - 2186 

题目大意是有n头牛,他们有m对特殊的关系

关系A B表示A仰慕B 恩 是感觉怪怪的= =

然后如果A仰慕B B仰慕C 那么A也仰慕C 也就是关系是可传递的

要求找出被其他牛都仰慕的牛的数目


一开始很费解,要不是放在强连通里,实在没法往这方向靠……

其实反过来想的话比较好像,强连通分支的定义——强连通分支中从任何一个点都可以访问到其余各点(有向图)

这样再回到题中 可以得出两个结论

1.如果某个强联通分支中的某只牛被分支外的所有牛都仰慕,也就是说分支外的牛都有一条通向他的路,和他在同一个强连通分支里的所有牛也是满足要求的。

2.如果分支中有某头牛仰慕分支外的牛,那么就不存在被所有牛都仰慕的牛。(可以换种方式来想,如果分支中某头牛仰慕分支外的牛,还被其余牛都仰慕,那么分支外的这头牛也应该被包含在分支内。因为这样就说明分支外的那头牛,会有一条通向分支内的路径,也就是符合强连通分量的定义)

3.经2结论可知,出度为0的强连通分支,就是满足条件的牛群。但如果有两群,就不存在这种牛。因为两个分支间是没有关系的。可以自己画一画看看。


找到方法判断就好办了,首先把所有的强连通分支求出来,缩点后变成一团团的。找出出度为0的缩点。如果存在两个或两个以上,答案就是0。如果之存在一个,那么这个点中的所有牛都是满足题意的牛,统计输出即可。


#include <bits/stdc++.h>
using namespace std;
const int maxn = 50005;
vector<vector<int> >G;
int low[maxn],dfn[maxn],color[maxn],stk[maxn];
bool instack[maxn];
int in[maxn],out[maxn];
int top,ti,cnt,n,m,sum,temp;
void tarjan(int u)
{
    int v;
    low[u]=dfn[u]=++ti;
    stk[top++]=u;
    instack[u]=1;
    for(int i=0; i<G[u].size(); i++)
    {
        v=G[u][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instack[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        cnt++;
        do
        {
            v=stk[--top];
            instack[v]=false;
            color[v]=cnt;
        }
        while(v!=u);
    }
}
void solve()
{
    memset(instack,0,sizeof(instack));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(color,0,sizeof(color));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    top=ti=cnt=sum=0;
    for(int i=1; i<=n; i++)
        if(dfn[i]==0)
        {
            tarjan(i);
        }
    for(int i=1; i<=n; i++)
        for(int j=0; j<G[i].size(); j++)
        {
            int nextone=G[i][j];
            if(color[i]!=color[nextone])
                out[color[i]]++;
        }
    for(int i=1; i<=cnt; i++)
        if(out[i]==0)
        {
            sum++;
            temp=i;
        }
    if(sum==1)
    {
        int ans=0;
        for(int i=1; i<=n; i++)
        {
            if(color[i]==temp)
                ans++;
        }
        cout<<ans<<endl;
    }
    else
    {

        cout<<0<<endl;
    }
}
int main()
{
    int x,y;
    while(cin>>n>>m)
    {
        G.clear();
        G.reserve(n+1);
        while(m--)
        {
            cin>>x>>y;
            G[x].push_back(y);
        }
        solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/beposit/article/details/80901757