POJ 1848 Tree

Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 2564   Accepted: 859

Description

Consider a tree with N vertices, numbered from 1 to N. Add, if it is possible, a minimum number of edges thus every vertex belongs to exactly one cycle.

Input

The input has the following structure: 

x(1) y(1) 
x(2) y(2) 
... 
x(N-1) y(n-1) 
N (3 <= N <=100) is the number of vertices. x(i) and y(i) (x(i), y(i) are integers, 1 <= x(i), y(i) <= N) represent the two vertices connected by the i-th edge. 

Output

The output will contain the value -1 if the problem doesn't have a solution, otherwise an integer, representing the number of added edges.

Sample Input

7
1 2
1 3
3 5
3 4
5 6
5 7

Sample Output

2

Source

Romania OI 2002
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INF 100

#define MAXN 110
#define MAXE 220
struct LEdge{
	int ed, next;
}edge[MAXE];
int head[MAXN], nEdge;

void init(){
	nEdge = 0;
	memset(head, 0xff, sizeof(head));
}

void addEdge(int i, int j){
	edge[nEdge].ed = j;
	edge[nEdge].next = head[i];
	head[i] = nEdge++;
}

int f[MAXN][3];

int imin(int a, int b){
	if (a < 0) return b;
	if (b < 0) return a;
	return a < b ? a : b;
}

int dfs(int pre, int cur){
	int i, j, k, p, q, sum;
	sum = 0;
	for (i = head[cur]; i != -1; i = edge[i].next){
		k = edge[i].ed;
		if (k == pre) continue;
		if (!dfs(cur, k)) return 0;
		sum += f[k][0];
	}
	f[cur][0] = f[cur][1] = f[cur][2] = INF;
	f[cur][1] = sum;
	for (i = head[cur]; i != -1; i = edge[i].next){
		p = edge[i].ed;
		if (p == pre) continue;
		f[cur][0] = imin(f[cur][0], f[p][2] - f[p][0] + sum + 1);
		f[cur][2] = imin(f[cur][2], f[p][2] - f[p][0] + sum);
		f[cur][2] = imin(f[cur][2], f[p][1] - f[p][0] + sum);
		for (j = edge[i].next; j != -1; j = edge[j].next){
			q = edge[j].ed;
			if (q == pre) continue;
			f[cur][0] = imin(f[cur][0], f[p][1] - f[p][0] + f[q][1] - f[q][0] + sum + 1);
			f[cur][0] = imin(f[cur][0], f[p][2] - f[p][0] + f[q][1] - f[q][0] + sum + 1);
			f[cur][0] = imin(f[cur][0], f[p][1] - f[p][0] + f[q][2] - f[q][0] + sum + 1);
			f[cur][0] = imin(f[cur][0], f[p][2] - f[p][0] + f[q][2] - f[q][0] + sum + 1);			
		}
	}
//	printf("cur = %d, f[0] = %d, f[1] = %d, f[2] = %d, t = %d, p = %d, q = %d, r = %d\n", cur, f[cur][0], f[cur][1], f[cur][2], t, p, q, r);
	if (f[cur][0] >= INF && f[cur][1] >= INF && f[cur][2] >= INF)
		return 0;
	return 1;
}

int main(){
	int i, j, k, n;
	while(scanf("%d", &n) != EOF){
		init();
		for (k = 1; k < n; k++){
			scanf("%d%d", &i, &j);
			addEdge(i, j);
			addEdge(j, i);
		}
		if (!dfs(0, 1) || f[1][0] >= INF) f[1][0] = -1;
		printf("%d\n", f[1][0]);
	}	
	return 0;
}

/*
f[i][0] i及其以下已成环
f[i][1] 仅i没成环
f[i][2] i带着一个长至少为2的链

f[i][0] = min(
	f[p][1] + f[q][1] + sum(f[其他][0]) + 1, 
	f[p][2] + f[q][1] + sum(f[其他][0]) + 1, 
	f[p][1] + f[q][2] + sum(f[其他][0]) + 1, 
	f[p][2] + f[q][2] + sum(f[其他][0]) + 1, 
	f[p][2] + sum(f[其他][0]) + 1)
f[i][1] = sum(f[其他][0])
f[i][2] = min(
	f[p][2] + sum(f[其他][0]),
	f[p][1] + sum(f[其他][0]))

开始无效值是-1,虽然做了好多好多特判
例如,有的子树本身无法全部成环,这样的点如果有一个,
可以通过和当前点组成环,或者和其他链组成环,或者作为当前点的链
如果有两个,则必须把他俩连一块
如果多于两个,说明无解
但是都WA掉了
后来看了网上的,没那么多特判,枚举起来也特暴力
初值设的INF,于是改成比较暴力的二重循环,而不是一重去找,
写的简单了,也就过了
经验: 尽量简洁,卡住了就释放些暴力	
*/


你可能感兴趣的:(POJ 1848 Tree)