uva 610 - Street Directions(双联通)

题目链接:uva 610 - Street Directions


求出所有边双联通分量,然后每一块单独考虑即可。


#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
typedef pair<int,int> pii;
const int maxn = 1005;
const int maxm = 1e6;

int N, M, E, first[maxn], jump[maxm], link[maxm], vis[maxm];
int cntlock, pre[maxn], low[maxn], iscut[maxm];

void dfs (int u, int fa) {
	pre[u] = low[u] = ++cntlock;

	for (int i = first[u]; i != -1; i = jump[i]) {
		int v = link[i];
		if (!pre[v]) {
			dfs(v, u);
			low[u] = min(low[u], low[v]);
			if (low[v] > pre[u])
				iscut[i] = 1;
		} else if (pre[v] < pre[u] && v != fa)
			low[u] = min(low[u], pre[v]);
	}
}

void findEdge () {
	cntlock = 0;
	memset(pre, 0, sizeof(pre));
	memset(iscut, 0, sizeof(iscut));
	for (int i = 1; i <= N; i++)
		if (!pre[i]) dfs(i, -1);
}

inline void addEdge (int u, int v) {
	jump[E] = first[u];
	link[E] = v;
	first[u] = E++;
}

void init () {
	E = 0;
	memset(first, -1, sizeof(first));

	int u, v;
	while (M--) {
		scanf("%d%d", &u, &v);
		addEdge(u, v);
		addEdge(v, u);
	}
	findEdge();
}

void put (int u) {
	if (pre[u]) return;

	pre[u] = ++cntlock;

	for (int i = first[u]; i != -1; i = jump[i]) {
		int v = link[i];
		if (iscut[i]) {
			printf("%d %d\n", u, v);
			continue;
		}
		if (vis[i]) continue;
		vis[i] = vis[i^1] = 1;
		printf("%d %d\n", u, v);
		put(v);
	}
}

void solve () {
	cntlock = 0;
	memset(pre, 0, sizeof(pre));
	memset(vis, 0, sizeof(vis));
	for (int i = 1; i <= N; i++)
		put(i);
}

int main () {
	int cas = 1;
	while (scanf("%d%d", &N, &M) == 2 && N + M) {
		init();
		printf("%d\n\n", cas++);
		solve();
		printf("#\n");
	}
	return 0;
}


你可能感兴趣的:(uva 610 - Street Directions(双联通))