BZOJ2466: [中山市选2009]树
BZOJ2466: [中山市选2009]树
https://lydsy.com/JudgeOnline/problem.php?id=2466
分析:
- 半年前写的高斯消元调不出来了。
- 现在来看这道题不是沙茶树形dp?
- 设\(f[x][0/1][0/1]\)表示\(x\)的子树不包含\(x\)都亮了,\(x\)按没按,\(x\)亮不亮。
- 然后转移即可。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <iostream>
#include <cmath>
#include <set>
using namespace std;
#define N 150
int head[N],to[N<<1],nxt[N<<1],cnt,n,f[N][2][2];
inline void add(int u,int v) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
int vis[N][2];
void dfs(int x,int y) {
int i;
f[x][1][0]=f[x][1][1]=1;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
dfs(to[i],x);
}
int mn[2],cc[2]; mn[0]=mn[1]=cc[0]=cc[1]=0;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
int t=to[i];
if(f[t][0][0]<f[t][1][0]) {
mn[0]+=f[t][0][0];
vis[t][0]=0;
}else {
mn[0]+=f[t][1][0];
cc[0]++;
vis[t][0]=1;
}
if(f[t][0][1]<f[t][1][1]) {
mn[1]+=f[t][0][1];
vis[t][1]=0;
}else {
mn[1]+=f[t][1][1];
cc[1]++;
vis[t][1]=1;
}
}
int d;
d=n+1;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
int t=to[i];
if(vis[t][1]==0) d=min(d,f[t][1][1]-f[t][0][1]);
else d=min(d,f[t][0][1]-f[t][1][1]);
}
if(cc[1]&1) {
f[x][0][1]=mn[1];
f[x][0][0]=mn[1]+d;
}else {
f[x][0][0]=mn[1];
f[x][0][1]=mn[1]+d;
}
d=n+1;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
int t=to[i];
if(vis[t][0]==0) d=min(d,f[t][1][0]-f[t][0][0]);
else d=min(f[t][0][0],f[t][1][0]);
}
if(cc[0]&1) {
f[x][1][0]+=mn[0];
f[x][1][1]+=mn[0]+d;
}else {
f[x][1][1]+=mn[0];
f[x][1][0]+=mn[0]+d;
}
}
int main() {
while(scanf("%d",&n)!=EOF&&n) {
memset(f,0,sizeof(f));
memset(head,0,sizeof(head)); cnt=0;
int i,x,y;
for(i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs(1,0);
printf("%d\n",min(f[1][0][1],f[1][1][1]));
}
}