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]));
	}
}
posted @ 2019-01-01 19:06  fcwww  阅读(266)  评论(0编辑  收藏  举报