【POJ 2186】Popular Cows

http://poj.org/problem?id=2186
tarjan求强连通分量。
因为SD省选用WinXP+Cena评测而且不开栈,所以dfs只好写手动栈了。
写手动栈时思路清晰一点应该是不会出错的吧。。。
这里tarjan要开两个栈,一个是tarjan用来记录强连通分量的栈,另一个是记录dfs路径的栈。
cur记录当前弧,fa记录dfs树上的father。
对于扫到一个环不需要dfs下去的情况就直接处理,对于需要dfs下去的情况就把下一个点压入栈,记录这下一个点的fa为当前点,同时当前点的cur向下一个位置跳一下。
dfs时经常需要当前点dfs所有它的dfs树上的孩子然后统计它的孩子的信息,如果写手动栈记录哪个后继节点被dfs了需要统计信息和哪个后继节点没有被dfs(这只是图上的情况,树上显然所有后继节点都必须被dfs)不需要统计信息就非常麻烦了。
有一个比较巧的做法是记录上述的fa,如果一个点的当前弧都跳完了,说明这个点的信息都处理好了,然后把这个点的信息传到它的fa上,它的fa就不需要记录哪个后继节点需要统计信息哪个后继节点不需要统计信息了。

#include<cstdio>
#include<bitset>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 10003;
const int M = 50003;

bitset <N> inst;
struct node {int nxt, to;} E[M];
int dfn[N], low[N], tot = 0, fa[N], bel[N], sta[N], statop = 0, st[N], top, cnt = 0, point[N], cur[N], n, m;

void ins(int u, int v) {E[++cnt] = (node) {point[u], v}; point[u] = cnt;}

void tarjan(int x) {
	st[top = 1] = x;
	while (top) {
		int u = st[top];
		if (!dfn[u]) {
			inst[u] = 1; sta[++statop] = u;
			low[u] = dfn[u] = ++cnt;
		}
		if (cur[u]) {
			int v = E[cur[u]].to;
			if (inst[v]) low[u] = min(low[u], dfn[v]);
			else if (!dfn[v]) fa[st[++top] = v] = u;
			cur[u] = E[cur[u]].nxt;
		} else {
			low[fa[u]] = min(low[fa[u]], low[u]);
			if (low[u] == dfn[u]) {
				++tot;
				while (sta[statop] != u) {
					bel[sta[statop]] = tot;
					inst[sta[statop]] = 0;
					--statop;
				}
				inst[u] = 0;
				bel[u] = tot; --statop;
			}
			--top;
		}
	}
}

int du[N];

int main() {
	int u, v;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d", &u, &v);
		ins(u, v);
	}
	for (int i = 1; i <= n; ++i)
		cur[i] = point[i];
	
	cnt = 0;
	for (int i = 1; i <= n; ++i)
		if (!dfn[i]) tarjan(i);
	
	for (int i = 1; i <= n; ++i)
		for (int j = point[i]; j; j = E[j].nxt)
			if (bel[i] != bel[E[j].to])
				++du[bel[i]];
	
	int mark = 0;
	for (int i = 1; i <= tot; ++i)
		if (du[i] == 0)
			if (mark == 0)
				mark = i;
			else
				{puts("0"); return 0;}
	
	int ret = 0;
	for (int i = 1; i <= n; ++i)
		if (bel[i] == mark)
			++ret;
	printf("%d
", ret);
	return 0;
}
原文地址:https://www.cnblogs.com/abclzr/p/6639707.html