【POJ 3177】Redundant Paths

http://poj.org/problem?id=3177
又写了一遍手动栈。。。
把边双都缩点,缩成一棵树,答案就是树中度数为1的点的个数除2上取整。
为什么呢?因为1个度数为1的点的树需要多连0条边,2个度数为1的点的树需要多连1条边,3个度数为1的点的树需要多连2条边。
然后对于n(n>3)个度数为1的点的树,连一次边后再缩点能变成有n-2个度数为1的点的树。
无向图边双跟有向图强连通分量的求法很像喔,重点在于特判后继节点是否是自己的father连过来的边。

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

const int N = 5003;
const int M = 10003;

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

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[sta[++statop] = u] = 1;
			dfn[u] = low[u] = ++cnt;
		}
		if (cur[u]) {
			if (cur[u] == fae[u]) {cur[u] = E[cur[u]].nxt; continue;}
			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, fae[v] = cur[u] ^ 1;
			cur[u] = E[cur[u]].nxt;
		} else {
			low[fa[u]] = min(low[fa[u]], low[u]);
			if (dfn[u] == low[u]) {
				++tot;
				while (sta[statop] != u) {
					bel[sta[statop]] = tot;
					inst[sta[statop]] = 0;
					--statop;
				}
				bel[u] = tot;
				inst[u] = 0;
				--statop;
			}
			--top;
		}
	}
}

int du[N];

int main() {
	scanf("%d%d", &n, &m);
	int u, v;
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d", &u, &v);
		ins(u, v); ins(v, u);
	}
	
	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] && E[j].to > i)
				++du[bel[i]], ++du[bel[E[j].to]];
	
	int ret = 0;
	for (int i = 1; i <= tot; ++i)
		if (du[i] == 1) ++ret;
	printf("%d\n", (ret + 1) >> 1);
	return 0;
}
posted @ 2017-03-29 17:01  abclzr  阅读(182)  评论(0编辑  收藏  举报