Popular Cows

Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

Input

* Line 1: Two space-separated integers, N and M

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.

Output

* Line 1: A single integer that is the number of cows who are considered popular by every other cow.

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

Hint

Cow 3 is the only cow of high popularity.

 

 

在同一个强连通分量中的点互相可以到达(互相崇拜),问题转化为将每个强连通分量压缩为点后新的图是否是DAG并且所有的点都可以到达最后一个点(SCC缩后)。

自己开始的思路是,用Kosaraju算法求好所有的scc后,拓扑序也已求好,在拓扑序中最后访问到的一个scc就是可能的答案,再以反向边从该点dfs,如果图中所有的点都能到达该点,那么该点所在的scc的结点数就是答案,否则不合法。

看题解,其思路更直观,缩点后新图判断出度为0的点个数,若为0,则整个图处于大scc中,若为1,则该点代表的scc结点数就是答案,若大于1,则不合法。因为只需要知道点的出度是不是0,不需要知道具体是多少,所以不需要新图建新边,直接遍历原边,若两点不在同一scc,就累加来源点的出度,同一scc每个点都算出度累加,就行了,不会影响结果正确性。

Kosaraju:

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
#define maxn 10000+1000

int n,m;
vector<int> G[maxn],G2[maxn];
vector<int> S;
int vis[maxn],sccno[maxn],scc_cnt;
int ans;

void AddEdge(int x,int y)
{
	G[x].push_back(y);
	G2[y].push_back(x);
}
void dfs1(int u)
{
	if(vis[u])return ;
	vis[u]=1;
	for(int i=0;i<G[u].size();i++)dfs1(G[u][i]);
	S.push_back(u);
}
void dfs2(int u)
{
	if(sccno[u])return ;
	sccno[u]=scc_cnt;
	for(int i=0;i<G2[u].size();i++)dfs2(G2[u][i]);
}
void dfs(int u)
{
	if(vis[u])return ;
	vis[u]=1;
	for(int i=0;i<G2[u].size();i++)dfs(G2[u][i]);
}
void find_scc()
{
	for(int i=1;i<=n;i++)dfs1(i);
	for(int i=n-1;i>=0;i--)if(!sccno[S[i]])
	{
		scc_cnt++;
		dfs2(S[i]);
	}
}
int check()
{
	int last;
	memset(vis,0,sizeof(vis));
	for(int i=n-1;i>=0;i--)if(!vis[sccno[S[i]]])last=S[i],vis[sccno[S[i]]]=1;
	bool ok=1;
	memset(vis,0,sizeof(vis));
	dfs(last);
	for(int i=1;i<=n;i++)if(!vis[i])ok=0;
	if(ok)for(int i=1;i<=n;i++)if(sccno[i]==sccno[last])ans++;
	return ans;
}

int main()
{
//	freopen("input.in","r",stdin);
	int x,y;
	scanf("%d%d",&n,&m);
	while(m--)
	{
		scanf("%d%d",&x,&y);
		AddEdge(x,y);
	}
	find_scc();
	printf("%d\n",check());
	return 0;
}

Tarjan:

#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
using namespace std;
#define maxn 10000+1000

int n,m;
vector<int> G[maxn];
stack<int> S;
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;

void dfs(int u)
{
	pre[u]=lowlink[u]=++dfs_clock;
	S.push(u);
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(!pre[v])
		{
			dfs(v);
			lowlink[u]=min(lowlink[u],lowlink[v]);
		}
		else if(!sccno[v])
		{
			lowlink[u]=min(lowlink[u],pre[v]);
		}
	}
	if(lowlink[u]==pre[u])
	{
		scc_cnt++;
		for(;;)
		{
			int x=S.top();S.pop();
			sccno[x]=scc_cnt;
			if(x==u)break;
		}
	}
}
void find_scc()
{
	for(int i=1;i<=n;i++)if(!pre[i])dfs(i);
}
int check()
{
	int out[maxn]={0};
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<G[i].size();j++)
		{
			if(sccno[i]!=sccno[G[i][j]])out[sccno[i]]++;
		}
	}
	int cnt=0;
	for(int i=1;i<=scc_cnt;i++)if(out[i]==0)cnt++;
	if(cnt>1)return 0;
	else if(cnt==0)return n;
	else for(int i=1;i<=scc_cnt;i++)if(out[i]==0)
	{
		int ans=0;
		for(int j=1;j<=n;j++)if(sccno[j]==i)ans++;
		return ans;
	}
}

int main()
{
//	freopen("input.in","r",stdin);
	int x,y;
	scanf("%d%d",&n,&m);
	while(m--)
	{
		scanf("%d%d",&x,&y);
		G[x].push_back(y);
	}
	find_scc();
	printf("%d\n",check());
	return 0;
}

 

全部评论

相关推荐

不愿透露姓名的神秘牛友
07-11 12:31
以前小时候我最痛恨出轨、偷情的人,无论男女,为什么会出轨?现在我成了自己最讨厌的人,没想到分享的东西在牛客会被这么多人看,大家的评价都很中肯,我也认同,想过一一回复,但我还是收声了,我想我应该说说这件事,这件事一直压在我心里,是个很大的心结,上面说了人为什么出轨,我大概能明白了。我们大一下半年开始恋爱,开始恋爱,我给出了我铭记3年的承诺,我对她好一辈子,我永远不会背叛,我责任心太重,我觉得跟了我,我就要照顾她一辈子,我们在一起3年我都没有碰过她,她说往东我就往东,她说什么我做什么,她要我干什么,我就干什么!在学校很美好,中途也出过一些小插曲,比如男闺蜜、男闺蜜2号等等等。但我都强迫她改掉了,我...
牛客刘北:两个缺爱的人是没有办法好好在一起的,但世界上哪有什么是非对错?你后悔你们在一起了,但是刚刚在一起的美好也是真的呀,因为其他人的出现,你开始想要了最开始的自己,你的确对不起自己,21岁的你望高物远,你完全可以不谈恋爱,去过你想要的生活,你向往自由,在一起之后,你要想的不是一个人,而是两个人,你不是变心了,就像你说的,你受够了,你不想包容了,冷静几天是你最优的选择,爱人先爱己。
社会教会你的第一课
点赞 评论 收藏
分享
一表renzha:不是你说是南通我都没往那方面想,人家真是想表达那个意思吗?
点赞 评论 收藏
分享
zYvv:双一流加大加粗再标红,然后广投。主要是获奖荣誉不够,建议开始不用追求大厂,去别的厂子刷下实习。
点赞 评论 收藏
分享
这算盘打的
程序员小白条:都这样的,都是潜规则,你自己说可以实习一年就行了,实习可以随便跑路的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务