J - Popular Cows

本题的题意是找最受欢迎的牛的数量,那么最受欢迎的牛是怎么定义的呢:除了他本身之外的所有牛都认为他是受欢迎的,其中a认为b是受欢迎的,b认为c是受欢迎的,那么a认为c是受欢迎的。
题解:想一想如果是一条长链,从1一直指向n那么就只有一个,如果其中有两条边指向不同位置而且没有形成环答案就是0,4没有指向5,5也没有指向4,那么4只有3只牛认为他是受欢迎的,没有n-1只,所以答案是0,成环的话就自己话一下吧,我不想画了,成环的时候环内的所有牛都认为其他牛是受欢迎的,那么就可以把环看成一个点然后就和这种图差不多了,但是答案如果最后是那个环,那么环内的元素的多少是答案。
在这里插入图片描述

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define se second
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const ll maxn = 5e4 + 50;
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;
const ll  lnf  = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e8;
const  double pi=3.141592653589;
vector<int>ve[maxn];
int n,m,x,y,out[maxn];
int idex=0,sum=0;
int dfn[maxn],low[maxn],bel[maxn],cnt[maxn],vis[maxn];
stack<int>s;
void tarjan(int u)
{
    dfn[u]=low[u]=++idex;
    s.push(u);
    vis[u]=1;
    for(int i=0;i<ve[u].size();i++)
    {
        int v=ve[u][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);//这里注意是两个low
        }
        else if(vis[v])low[u]=min(low[u],dfn[v]);//这里一个是low一个是dfn
    }
    if(dfn[u]==low[u])//说多了也就是找到了一个强连通图//也就是一种可以从任意环上任意一点出发转一圈后可以回到原点的环或者就是一个点
    {
        sum++;
        int v;
        bel[u]=sum;
        do
        {
            v=s.top();
            bel[v]=sum;//把这个环内所有点染色成sum
            s.pop();//出栈
            vis[v]=0;//标记出栈
            cnt[sum]++;//记录该环有多少个元素
        }while(u!=v);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        ve[u].push_back(v);
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
            tarjan(i);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<ve[i].size();j++)
        {
            int nw=ve[i][j];
            if(bel[i]!=bel[nw])//记录强连通图的中元素除连强连通图外的出边
            {
                out[bel[i]]++;
            }
        }
    }
    int ans=0;
    bool flage=true;
    for(int i=1;i<=sum;i++)//如果一个强连通图有中的某个元素有出到另外的地方的出边就不满足题意
    {
        if(!out[i])
        {
            if(!ans)
            {
              ans=cnt[i];
            }
            else
            {
                flage=false;
                break;
            }
        }
    }
    if(flage)
    {
        printf("%d\n",ans);
    }
    else
    {
        printf("0\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qcccc_/article/details/107403928