天天看點

poj 3352 Road Construction 邊雙連通縮點

題意:給你一個圖,問至少需要加多少條路使得整個圖成為邊雙連通。

求出割邊并縮點,可以得到一棵樹,統計樹上所有度為1的點數,最後的答案就是(cnt+1)/2,這個畫個圖就明白了。

ps:這題坑了我兩個wa,輸入和輸出原來不需要Sample Input 1。。太坑了

#include <stdio.h>
#include <string.h>

const int maxn = 1002;
const int maxm = 1005;
struct EDGE{
	int to, next, vis;
}edge[maxm<<1];

int head[maxn], dfn[maxn], belo[maxn], low[maxn], st[maxn];
int E, time, top, gtot, type;

struct GEDGE{
	int u, to;
}gedge[maxm];

void newedge(int u, int to) {
	edge[E].to = to;
	edge[E].next = head[u];
	edge[E].vis = 0;
	head[u] = E++;
}

void init() {
	memset(head, -1, sizeof(head));
	memset(dfn, 0, sizeof(dfn));
	memset(belo, 0, sizeof(belo));
	E = time = type = top = gtot = 0;
}

int min(int a, int b) {
	return a > b ? b : a;
}

void dfs(int u) {
	dfn[u] = low[u] = ++time;
	st[++top] = u;
	for(int i = head[u];i != -1;i = edge[i].next) {
		if(edge[i].vis)	continue;
		edge[i].vis = edge[i^1].vis = 1;
		int to = edge[i].to;
		if(!dfn[to]) {
			dfs(to);
			low[u] = min(low[u], low[to]);
			if(low[to] > dfn[u]) {
				type++;
				int v;
				do {
					v = st[top--];
					belo[v] = type;
				} while(v != to);
				gedge[gtot].u = u;
				gedge[gtot++].to = to; 
			}
		}
		else
			low[u] = min(low[u], low[to]);
	}
}

int ans ;
void DFS(int u, int pre) {
	int tot = 0;
	if(pre != -1)	tot++;
	for(int i = head[u];i != -1;i = edge[i].next) {
		int to = edge[i].to;
		if(to != pre) {
			DFS(to, u);
			tot++;
		}
	}
	if(tot == 1)	ans++;
}

char s[111];
int main() {
	int n, m, i, u, to;
	while(scanf("%d%d", &n, &m) != -1) {
		init();
		for(i = 0;i < m;i ++) {
			scanf("%d%d", &u, &to);
			newedge(u, to);
			newedge(to, u);
		}
		for(i = 1;i <= n; i++) if(!dfn[i])
			dfs(i);
		memset(head, -1, sizeof(head));
		E = 0;
		for(i = 0;i < gtot; i++) {
			u = belo[gedge[i].u];
			to = belo[gedge[i].to];
			newedge(u, to);
			newedge(to, u);
		}
		ans = 0;
		DFS(0, -1);
		printf("%d\n", (ans+1)/2);
	}
	return 0;
}
           

繼續閱讀