受欢迎的牛(tarjan)

题目链接:受欢迎的牛

题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你算出有多少头奶牛可以当明星。

输入格式
第一行:两个用空格分开的整数:N和M
第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B

输出格式
第一行:单独一个整数,表示明星奶牛的数量

输入

3 3
1 2
2 1
2 3

输出

1

说明/提示
只有 3 号奶牛可以做明星

【数据范围】

10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000jieti

解题思路

这个题是个强连通的模板题,今天刚学就拿这个题练练手吧。如果你还不知道强连通不知道tarjan请忽略此题,因为刚开始所以我用的tarjan写的。
我们先用tarjan进行缩点,也就是将一个环染成一种颜色,最后按照颜色进行操作就可以了,这样就能省下很多时间,并且可以没有遗漏,我们将每个节点染完色以后看看,那些个颜色的入度为零,如果只有一个,那么就这个颜色的节点就都是最受欢迎的,如果没有或者多余一个那么就没有最受欢迎的了。

代码

#include <bits/stdc++.h>
using namespace std;
const int MX=1e6;
int dfn[MX],low[MX];
int cnt;//dfs遍历到第几个点 
int du[MX];//统计度数 
int color[MX],color_num[MX];//每个节点属于哪个颜色,每种颜色有几个 
int sum,n,m;//sum为一共有多少颜色 
vector<int>ve[MX];//存图 
stack<int>st;
bool vis[MX];//标记是否在栈中 

void tarjon(int x)
{
    dfn[x]=low[x]=++cnt;
    st.push(x);
    vis[x]=1;
    for(int i:ve[x])
    {
        if(!dfn[i]){//如果dfn 为零说明还没遍历过就遍历这个点 
            tarjon(i);
            low[x]=min(low[i],low[x]);//更新low的值 
        }
        else if(vis[i])//如果遍历过了,切在栈里面就直接更新 low 的值就行了 
        {
            low[x]=min(low[x],dfn[i]);
        }
    }
    int k;
    if(low[x]==dfn[x])//如果 low 等于 dfn 说明这个点为一个联通分量 
    {
    	sum++;//每一个联通分量为一种颜色 
    	do
    	{
        	k=st.top();//将栈的最顶端元素取出来 
        	st.pop();
        	vis[k]=0;//恢复标记 
        	color[k]=sum; //点k属于颜色 sum 
        	color_num[sum]++;//颜色 sum 的节点数加一 
   	 	}while(k!=x);//遍历该联通分量的元素被遍历完; 
	}
   
}

int main()
{
    cin>>n>>m;
    for(int x,y,i=0;i<m;i++)
    {
        cin>>x>>y;
        ve[x].push_back(y);
    }
    for(int i=1;i<=n;i++)//遍历图,如果该点的dfn为空就遍历这个节点 
    {
        if(!dfn[i]) tarjon(i);
    }
    for(int i=1;i<=n;i++)//统计度数 
    {
        for(int j:ve[i])
        {
            if(color[i]!=color[j]) du[color[i]]++;//如果颜色不同就让 j 颜色的度数加一 
        }
    }
    int cow_max=0;
    for(int i=1;i<=sum;i++)
    {
        if(!du[i])//最受欢迎的牛的出度一定唯一,所以看谁的出度是一 
        {
            if(cow_max) {//如果两个出度为一的点说明没有最受欢迎的牛 
                cout<<"0\n";
                return 0;
            }
            cow_max=i;
        }
    }
    cout<<color_num[cow_max]<<'\n';//输出最后节点的联通分量的个数 
    return 0;
}
发布了49 篇原创文章 · 获赞 14 · 访问量 4345

猜你喜欢

转载自blog.csdn.net/qq_43750980/article/details/103979822