poj1848 Tree

.....是我多想了。

我想开f[][0~3],看到百度上的题解都是[0~2]的,我就改了

方程不是特别难想。。

f代表最小代价

f[i][0]是子树有环过i

f[i][1]是子树除了i都成环了

f[i][2]是子树有条链过i(最少2个点,包括i)

转移见代码(有状态了转移很好想)。

/**
 * Problem:POJ1848
 * Author:Shun Yao
 * Time:2013.9.2
 * Result:Accepted
 * Memo:TreeDP
 */

#include <cstdio>

#define MAXN 110
#define inf 1000

long f[MAXN][3];

long min(long x, long y) {
	return x < y ? x : y;
}

class Edge {
public:
	long v;
	Edge *next;
	Edge() {}
	~Edge() {}
	Edge(long V, Edge *ne) : v(V), next(ne) {}
} *g[MAXN];

void add(long x, long y) {
	g[x] = new Edge(y, g[x]);
	g[y] = new Edge(x, g[y]);
}

void dp(long i, long pa) {
	long sum;
	Edge *e;
	sum = 0;
	for (e = g[i]; e; e = e->next)
		if (e->v != pa) {
			dp(e->v, i);
			sum += f[e->v][0];
		}
	f[i][2] = inf;
	f[i][0] = inf;
	f[i][1] = sum;
	if (g[i]->v == pa && !g[i]->next)
		return;
	static long x, y, z;
	x = inf;
	y = inf;
	for (e = g[i]; e; e = e->next)
		if (e->v != pa) {
			f[i][2] = min(f[i][2], f[e->v][1] - f[e->v][0]);
			f[i][2] = min(f[i][2], f[e->v][2] - f[e->v][0]);
			f[i][0] = min(f[i][0], f[e->v][2] - f[e->v][0]);
			z = min(f[e->v][1], f[e->v][2]) - f[e->v][0];
			if (x > z) {
				y = x;
				x = z;
			} else if (y > z)
				y = z;
		}
	f[i][2] += sum;
	if (y < inf)
		f[i][0] = min(f[i][0], x + y);
	f[i][0] += sum + 1;
}

int main() {
	static long n, i, u, v;
	
#ifndef ONLINE_JUDGE
	freopen("poj1848.in", "r", stdin);
	freopen("poj1848.out", "w", stdout);
#endif

	scanf("%ld", &n);
	for (i = 1; i < n; ++i) {
		scanf("%ld%ld", &u, &v);
		add(u, v);
	}
	dp(1, 0);
	if (f[1][0] >= inf)
		printf("-1");
	else
		printf("%ld", f[1][0]);

	fclose(stdin);
	fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/hsuppr/p/3297003.html