POJ - 2186 Popular Cows

版权声明:博客作者为blue bear,严禁他人在未经作者同意下进行商用转载 https://blog.csdn.net/weixin_44354699/article/details/88373359

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.

输入 输出
3 3
1 2
2 1
2 3



1

Hint:Cow 3 is the only cow of high popularity.

题意

n牛m关系
a b表示a认为b很nb
如果a b又b c则有a c
问被其他所有牛认为都很nb的奶牛数量

分析

是一个有向图,tarjan找出强连通分量,然后把他看成一个点,做完以后你会得到一个有向无环图(有环就被缩点),所以找出度为0的点,如果这样点大于1个那他们谁也瞧不起谁,所以是0。当且仅当出度为0的点只有一个的时候,其他的点的牛都是他的舔狗。
tarjan算法,这篇“全网最详细”,我也不好再多解释,大家可以参照这位dl的解析。
至于缩点就是把同一联通块的点看作一个。
那么我这里是开一个id数组出栈的时候标记一下
再检查出度

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<functional>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=1e4+5;
const int INF=0x3f3f3f3f;
vector <int> edge[maxn];
int n,m,tot,dfn[maxn],low[maxn];//tarjan组件
int id[maxn],id_cnt,stack[maxn],top,sum[maxn];//id为属于哪个强联通块 后者为记录的栈 及记录联通块中点的个数
//用id[]记录是否在栈
void init(){
	tot=id_cnt=top=0;
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(id,0,sizeof(id));
	memset(stack,0,sizeof(stack));
	memset(sum,0,sizeof(sum));
	for(int i=0;i<=n;i++) edge[i].clear();
}
void tarjan(int x) {
	dfn[x]=low[x]=++tot;
	stack[++top]=x;
	for(int i=0; i<edge[x].size();i++) {
		if(!dfn[ edge[x][i] ]) {
			tarjan(edge[x][i]);
			low[x]=min(low[x],low[edge[x][i]]);
		} else if(!id[edge[x][i]]) { //出栈必有id 不入栈时为上一判断情况
			low[x]=min(low[x],dfn[edge[x][i]]);
		}
	}
	if(low[x]==dfn[x]) {
		id_cnt++;
		while(top) {
			int num=stack[top--];
			id[num]=id_cnt;
			sum[id_cnt]++;
			//printf("%d %d %d %d\n",num,x,id_cnt,sum[id_cnt]);
			if(num==x) break;
		}
	}
	return;
}
int main() {
	int from,to;
	scanf("%d%d",&n,&m);
	init();
	for(int i=0;i<m;i++) {
		scanf("%d%d",&from,&to);
		edge[from].push_back(to);
	}
	for(int i=1;i<=n;i++) {
		if(!dfn[i]) tarjan(i);
	}
	int out[maxn]={0};
	for(int i=1;i<=n;i++) {
		for(int j=0;j<edge[i].size();j++){
			if(id[i]!=id[ edge[i][j] ]){//不属于同一联通块 则为联通块的连线
				out[id[i]]++; 
				//printf("%d %d %d %d %d\n",i,id[i],out[id[i]],edge[i][j],id[edge[i][j]]);
			}
		}
	}
	int total=0,pos=0;
	for(int i=1;i<=id_cnt;i++) {
		if(out[i]==0){
			total++;
			pos=i;
		}
	}
	if(total!=1) puts("0");
	else printf("%d\n",sum[pos]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44354699/article/details/88373359
今日推荐