Popular Cows POJ - 2186 (强连通分量)

本文介绍了一种通过构建有向图并运用强连通分量算法来找出牛群中被认为最受欢迎的牛的数量的方法。该算法首先对每一对认为另一方流行的牛进行遍历,然后通过逆向遍历确定哪些牛被所有其它牛认为是流行的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Popular Cows

POJ - 2186

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.

题意:如果A认为B牛逼,B认为C牛逼,A也认为C牛逼(有向图),求有被所有牛都认为牛逼的牛的个数

用到强连通分量的模板,但不是单纯的求强连通分量

思路:

假设两头牛A和B都被其他所有牛人认为牛逼,所以A,B互相认为和牛逼,AB属于一个强连通分量,所以如果我们找到一个符合的强连通分量,那么这里面的所有点都牛逼

既然要被其他所有点都认为牛逼,那么应该选择强连通分量分解后拓扑序的最后一个强连通分量,但是还不一定正确,还要判断这强连通分量中的一点(只需要判断一点就可以了,因为强连通嘛)是否可以到达其他所有点,可以就输出这个强连通分量中点个数,否则为0

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
vector<int>G[10009],VG[10009];
vector<int>v;
int vis[10009];
int cmp[10009]; 
int n,m;
void dfs(int u){
	int i;
	vis[u] = 1;
	for(i = 0; i < G[u].size(); i++){
		if(!vis[G[u][i]])
		  dfs(G[u][i]);
	}
	v.push_back(u);
}

void redfs(int u,int k){
	int i;
	vis[u] = 1;
	cmp[u] = k;//求强连通分量的同时求出了每个分量的拓扑序 
	for(i = 0; i < VG[u].size(); i++){
		if(!vis[VG[u][i]]){
			redfs(VG[u][i],k);
		}
	}
}
int scc(){
	int i;
	memset(vis,0,sizeof(vis));
	for(i = 1; i <= n; i++){
		if(!vis[i])
		  dfs(i);
	}
	int cnt = 0;
	int k;//记录强连通分量的拓扑序 
	memset(vis,0,sizeof(vis));
	for(i = v.size()-1; i >= 0; i--){
		if(!vis[v[i]]){
			redfs(v[i],k++);
		}
	}
	return k;
}

void solve(){
	int cnt = scc();//进行强连通分量的分解,同事求出分量的拓扑序 
	int i;
	int num = 0;
	int u = 0;
	for(i = 1; i <= n; i++){
		if(cmp[i] == cnt-1){//寻找拓扑序最后的分量,统计个数,记录其中的一个点 
			u = i;
			num++;
		}
	}
	memset(vis,0,sizeof(vis));
	redfs(u,0);//从这个记录的点反向进行遍历如果是可以的,一定可以行遍所有的点 
	for(i = 1; i <= n; i++){
		if(!vis[i]){//因此一旦发现还有没遍历的点,说明一定是错误的输出0 
			num = 0;
			break;
		}
	}
	cout << num << endl;
}

int main(){
	cin >> n >> m;
	int i;
	for(i = 1; i <= m; i++){
		int u,v;
		cin >> u >> v;
		G[u].push_back(v);
		VG[v].push_back(u);
	}//读入 
    solve();//求解 
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值