1. 程式人生 > >BZOJ2466: [中山市選2009]樹

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]));
    }
}