一道树形dp卡了这么久。。。
题意:一个书中,每个点都可以安服务器,问最少多少服务器可以使每个不是服务器的点恰好只与一个服务器相邻
把每个点分情况讨论
1.自己安服务器 2.自己不安,父节点安,这样所有子节点不能安 3自己不安,父节点不安,这样有且只有一个子节点安
设dp[i][0]为i及其子树,当i安服务器时最少服务器。dp[i][2]表示i的父亲安儿子不安,dp[i][1]表示i的一个儿子安父亲不安
dp[i][0]可以从儿子中0,1转移,dp[i][2]只能从儿子中1转移
只有一个儿子安这种情况看起来麻烦一点,但是可以看成本来所有儿子都不安,这样就等于dp[i][2],然后选出一个儿子变成安,这样会产生一个差值,最后加上所有儿子中最小的差值
然后怒交一发,发现WA??然后xjb改都没有用,然后盯着代码看了半天脑洞一开发现自己INF按照习惯开的两千万,这样叶节点儿子安的情况是INF,但是如果有一个节点连了很多叶节点,转移的时候很有可能会爆INT。码力弱。。。
#include<iostream> #include<cstdio> #include<cstring> #define MAXN (20010) #define INF (210010) using namespace std; int n,m1,h[MAXN],dp[MAXN][3]; struct edge{ int next,to; void Add(int Next,int To){ next=Next; to=To; } }q[MAXN]; void addedge(int x,int y){ q[++m1].Add(h[x],y); h[x]=m1; q[++m1].Add(h[y],x); h[y]=m1; } void Dfs(int x,int fa){ int i,y,k=INF; dp[x][0]=1; dp[x][1]=dp[x][2]=0; for (i=h[x];i;i=q[i].next){ y=q[i].to; if (y==fa) continue; Dfs(y,x); dp[x][0]+=min(dp[y][0],dp[y][2]); dp[x][2]+=dp[y][1]; k=min(k,dp[y][0]-dp[y][1]); } dp[x][1]=dp[x][2]+k; } int main(){ while (cin>>n){ memset(h,0,sizeof(h)); memset(q,0,sizeof(q)); memset(dp,0,sizeof(dp)); m1=0; int x,y; for (int i=1;i<=n-1;i++){ scanf("%d %d",&x,&y); addedge(x,y); } scanf("%d",&x); Dfs(1,0); printf("%d\n",min(dp[1][0],dp[1][1])); if (x==-1) break; } }