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\n",g[1][0]);
getchar();getchar();
return 0;
}
人就像命运下的蝼蚁,谁也无法操控自己的人生.