BZOJ2466: [中山市選2009]樹
阿新 • • 發佈:2019-01-01
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])); } }