树形dp
dp[i][0]表示i是服务器
dp[i][1]表示i不是服务器,i父亲是
dp[i][2]表示u与u的父亲都不是
转移方程很显然
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int maxn = 1e4+10; int dp[maxn][3],n,size,head[maxn],ru[maxn]; struct edge{ int v,nex; }e[maxn<<1]; void adde(int u,int v) { e[size].v=v; e[size].nex=head[u]; head[u]=size++; } void dfs(int u,int fa) { dp[u][0]=1;dp[u][2]=dp[u][1]=0; int d=maxn;//注意不能是inf,不然会加爆 for(int i=head[u];~i;i=e[i].nex) { int v=e[i].v;if(v==fa) continue; dfs(v,u); dp[u][1]+=dp[v][2]; dp[u][0]+=min(dp[v][0],dp[v][1]); d=min(d,dp[v][0]-dp[v][2]); } dp[u][2]=dp[u][1]+d; } int main() { //freopen("in.txt","r",stdin); while(scanf("%d",&n)) { memset(head,-1,sizeof(head)); memset(ru,0,sizeof(ru)); size=0; for(int i=1;i<n;i++) { int u,v;scanf("%d%d",&u,&v); adde(u,v);adde(v,u);ru[v]++;ru[u]++; } dfs(1,0); printf("%d ",min(dp[1][0],dp[1][2])); int a;scanf("%d",&a);if(a==-1) break; } return 0; }