[HAOI2006]受欢迎的牛---强连通分量加缩点

题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶

牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜

欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你

算出有多少头奶牛可以当明星。

输入格式:
第一行:两个用空格分开的整数:N和M

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

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

输入样例
3 3
1 2
2 1
2 3
输出样例
1

简单地讲一下思路

这道题目的是让我们找被其他所有奶牛所欢迎的奶牛数量,我当时很奇怪,被除自己一外的牛都喜欢,不是肯定只有一个吗?然后我反应过来了,一个可以看出强连通分量的缩点,也就是说找那个可以被其他所有强连通分量通向的那个强连通分量,也就是只有入度没有出度的那个强连通分量。
如果缩点不会强连通------tarjan算法详解及与缩点联合运用可以参考一下
通过给每一个出度不为零的强连通分量赋值为1,剩下为零的就是只有入度没有出度的那个强连通分量。
这里需要判断如果图本身有多个为零的强连通,就说明没有一个强连通分量被其他所有强连通分量都喜欢。

#include<iostream>
#include<vector>
#include<stack>
#include<algorithm>

using namespace std;
const int maxn=1e4+3;
int n,m,flag,cnt,low[maxn],dfn[maxn],vis[maxn],tar[maxn],ru[maxn];
vector<int> vec[maxn];
stack<int> sta;
void tarjan(int x)
{
	vis[x]=1;
	low[x]=dfn[x]=++cnt;
	sta.push(x);
	for(int i=0;i<vec[x].size();i++)
	{
		int to=vec[x][i];
		if(!dfn[to])
		{
			tarjan(to);
			low[x]=min(low[x],low[to]);
		}
		else if(vis[x])
		low[x]=min(low[x],dfn[to]);
	}
	if(dfn[x]==low[x])
	{
		flag++;	
		int z;
		while(sta.top()!=x)
		{
		 z=sta.top();
			sta.pop();
			vis[z]=0;
			tar[z]=flag;
		}
		z=sta.top();
		sta.pop();
		vis[z]=0;
		tar[z]=flag;
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		cin>>x>>y;
		vec[x].push_back(y);
	}
	flag=0;
	cnt=0;
	for(int i=1;i<=n;i++)
	if(!dfn[i])
	   tarjan(i);

	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<vec[i].size();j++)
		{
			int to=vec[i][j];
			if(tar[i]!=tar[to])
			ru[tar[i]]=1;
		}
	}

	int p,flag1=0;
	for(int i=1;i<=flag;i++)
	{
		if(ru[i]==0)
		{
		p=i;
		flag1++;	
		}
	}
   if(flag1>1)
   {
   	cout<<"0";
   }
   else{
  
	int summ=0;
	for(int i=1;i<=n;i++)
	{
		if(tar[i]==p)
		{
			summ++;
		}
	}
	cout<<summ; }
	return 0;
 } 
发布了44 篇原创文章 · 获赞 4 · 访问量 1064

猜你喜欢

转载自blog.csdn.net/qq_44162236/article/details/104074971
今日推荐