Luogu2341 受欢迎的牛

好题。

在有向图中找到强连通子图,缩点,记上里面有几头牛,变成DAG。

然后找出出度为0的点。如果这样的点的数量不等于1显然输出0。否则答案就是这个点的原点数。

为了方便,反向建边,变统计出度为入度。枚举每一个原图的点u,如果找到原图中与u点相连的v不属于同一个scc,那么入度+1。(即不重建图。

打了四遍这个题真TM爽

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 10001
#define maxm 50001
using namespace std;
int head[maxn];
struct edge{
	int to, nxt;
}e[maxm];
int n, m, tot, top, cnt, col;
int dfn[maxn], st[maxn], low[maxn], scc[maxn];
int sl[maxn], ind[maxn];
void add(int u, int v){
	e[++tot].nxt=head[u];
	e[tot].to=v;
	head[u]=tot;
}
void tarjan(int u){
	dfn[u]=low[u]=++cnt;
	st[++top]=u;
	for(int i=head[u]; i; i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u], low[v]);
		}else if(!scc[v])
			low[u]=min(low[u], dfn[v]);
	}
	if(low[u]==dfn[u]){
		scc[u]=++col;
		++sl[col];
		while(st[top]!=u){
			++sl[col];
			scc[st[top]]=col;
			top--;
		}
		top--;
	}
}
int main(){
	scanf("%d%d", &n, &m);
	int x, y;
	for(int i=1; i<=m; i++){
		scanf("%d%d", &x, &y);
		add(y,x);
	}
	for(int i=1; i<=n; i++)
		if(!dfn[i]) tarjan(i);
	for(int i=1; i<=n; i++)
		for(int j=head[i]; j; j=e[j].nxt){
			int v=e[j].to;
			if(scc[i]!=scc[v])
				ind[scc[v]]++;
		}
	int ans=0, indtj=0;
	for(int i=1; i<=col; i++)
		if(!ind[i])
			ans=sl[i], indtj++;
	if(indtj==1)
		printf("%d", ans);
	else printf("0");
	return 0;
}
posted @ 2018-11-05 21:25  PushinL  阅读(142)  评论(0编辑  收藏  举报