bzoj 1369: Gem 树形dp

题目大意

给出一棵树,要求你为树上的结点标上权值,权值可以是任意的正整数 唯一的限制条件是相临的两个结点不能标上相同的权值,要求一种方案,使得整棵树的总价值最小。N<=10000

题解

我们可以猜一个结论,用到的编号不会超过某一个值
我们发现我们可以开到100以上都不会超时
所以我们把编号最多100算,跑树形dp即可
其实可以证明编号不会超过logn...

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
	x=0;char ch;bool flag = false;
	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 10010;
struct Edge{
	int to,next;
}G[maxn<<1];
int head[maxn],cnt;
void add(int u,int v){
	G[++cnt].to = v;
	G[cnt].next = head[u];
	head[u] = cnt;
}
inline void insert(int u,int v){
	add(u,v);add(v,u);
}
int f[maxn][22],g[maxn][4];
const int inf = 0x3f3f3f3f;
const int colnum = 3;
#define v G[i].to
void dfs(int u,int fa){
	for(int i=1;i<=colnum;++i) f[u][i] = i;
	for(int i = head[u];i;i=G[i].next){
		if(v == fa) continue;
		dfs(v,u);
		for(int j=1;j<=colnum;++j){
			if(g[v][0] == f[v][j]) f[u][j] += g[v][1];
			else f[u][j] += g[v][0];
		}
	}
	g[u][0] = g[u][1] = inf;
	int pos = -1;
	for(int i=1;i<=colnum;++i){
		if(f[u][i] < g[u][0]) g[u][0] = f[u][i],pos = i;
	}
	for(int i=1;i<=colnum;++i){
		if(i == pos) continue;
		g[u][1] = min(g[u][1],f[u][i]);
	}
}
#undef v
int main(){
	int n;read(n);
	int u,v;
	for(int i=1;i<n;++i){
		read(u);read(v);
		insert(u,v);
	}dfs(1,0);
	printf("%d
",g[1][0]);
	getchar();getchar();
	return 0;
}
原文地址:https://www.cnblogs.com/Skyminer/p/6417320.html