Popular Cows POJ - 2186(Tarjan+极大强连通分量+缩点 )

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.

题意: 每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
牛被所有的牛认为是受欢迎的。
思路: 根据求有多少头牛被所有的牛认为是受欢迎的,我们可以想求强连通分量,缩点之后求出一个没有出度的点,然后将该点内部的点计数就是答案。代码实现主要内容讲解在注释里。
知识储备: 强连通分量是什么。缩点的含义是什么,为了什么。targan算法的实现原理。

#include <string.h>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdexcept>
#include <string>
#include <vector>
using namespace std;
typedef unsigned long long ull;
#define ll long long
#define int long long
const int maxn = 2e5 + 100;
const int inf = 0x3f3f3f3f;
const int Base = 131;
const ll INF = 1ll << 62;
// const double PI = acos(-1);
const double eps = 1e-7;
const int mod = 1e9 + 7;
#define mem(a, b) memset(a, b, sizeof(a))
#define speed                        \
	{                                \
		ios::sync_with_stdio(false); \
		cin.tie(0);                  \
		cout.tie(0);                 \
	}


inline ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }

int n, m, deep, cnt;
int low[maxn], dfn[maxn], countx[maxn], color[maxn], out[maxn];
int isInStack[maxn];

vector<int>e[maxn];
stack<int>st;//栈操作便于返回同一强连通分量的点
void dfs(int u){//targan算法求low序和dfn序
	low[u] = dfn[u] = ++deep;
	st.push(u);
	isInStack[u] = 1;//标记是否在栈中
	for(int i = 0; i < e[u].size(); i++){
		int v = e[u][i];
		if(!dfn[v]){
			dfs(v);
			low[u] = min(low[u], low[v]);
		}
		else if(isInStack[v]){
			low[u] = min(low[u], dfn[v]);
		}
	}
	if(low[u] == dfn[u]){
		cnt++;
		int top;
		isInStack[u] = 0;
		color[u] = cnt;//染色
		do{
			top = st.top();
			color[top] = cnt;
			isInStack[top] = 0;
			st.pop();
		}while(u != top);
	}
}

int targan(int x){
	cnt = deep = 0;
	while(!st.empty())st.pop();
	for(int i = 0; i < x; i++){
		low[i] = 0;//最近祖先
		dfn[i] = 0;//dfs序
		isInStack[i] = 0;//是否在栈中
		countx[i] = 0;//统计同一强连通分量中的点数
		color[i] = 0;//染色
		out[i] = 0;//统计缩点后该点的出度
	}
	
	for(int i = 0; i < n; i++){
		if(!dfn[i]){
			dfs(i);
		}
	}
	return cnt;
}


signed main(){
	scanf("%lld", &n);
	scanf("%lld", &m);
	for(int i = 0; i < m; i++){
		int u, v;
		scanf("%lld %lld", &u, &v);
		e[u - 1].push_back(v - 1);
	}
	int tot = targan(n);//返回强连通分量数量
	for(int i = 0; i < n; i++){
		//一条边u->v,若u的颜色和v不同那么说明这两个点分别在两个强连通分量里面,
		//且u所在的缩点有到v所咋的缩点的单向路径
		countx[color[i]]++;
		for(int j = 0; j < e[i].size(); j++){
			if(color[i] != color[e[i][j]]){
				out[color[i]]++;//统计缩点后的点出度
			}
		}
	}
	int flag = 0, p = -1;
	for(int i = 1; i <= cnt; i++){//判断是否只有一个缩点的出度为0
		if(out[i] == 0){
			flag++;
			if(flag == 2)break;
			p = i;
		}
	}
	if(flag == 1)printf("%lld\n", countx[p]);//输出该缩点内部点的数量
	else printf("0\n");
	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值