题意:给n台机器形成无根树状结构,然后需要安装一些服务器,使得不是服务器的计算机恰好和一台服务器计算机相邻,问最少需要安装的服务器台数
题解:形成无根树状想到的必然是树形DP,其次很明显是对该点是不是服务器进行讨论。还有关键是恰好一台相邻。(没看到这个条件状态转移看了半天没看明白)
dp[u][0]:自己不是服务器,父亲是,所以所有子节点也不是
dp[u][1]:自己是服务器,子节点可以是也可以不是
dp[u][2]:自己和父亲都不是,所有有一个子节点必是
dp[u][0] = sum(dp[v][2])
dp[u][1] = sum(min(dp[v][1],dp[v][0])
dp[u][2] = min(dp[v’][1] + sum(dp[v”][2]))
= min(dp[v’][1] + sum(dp[v][2]) - dp[v’][2])
= min(dp[v’][1] + dp[u][0] - dp[v’][2])
还有个坑是dp[u][2]这个INF不能太大。我也是看了别人的才知道= =。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <map>
#include <vector>
#define INF 0x3f3f
using namespace std;
const int maxn = 1e5 + 5;
typedef long long LL;
vector <int> vec[maxn];
int dp[maxn][3];//dp[][0] 自己不是服务器但是父亲是, dp[][1]自己是服务器, dp[][2] 自己和父亲都不是服务器
void dfs(int u, int fa){
dp[u][0] = 0;
dp[u][1] = 1;
dp[u][2] = INF;
for(int i=0; i<vec[u].size(); i++){
int v = vec[u][i];
if(v == fa) continue;
dfs(v,u);
}
for(int i=0; i<vec[u].size(); i++){
int v = vec[u][i];
if(v == fa) continue;
dp[u][0] += dp[v][2];
dp[u][1] += min(dp[v][1], dp[v][0]);
}
for(int i=0; i<vec[u].size(); i++){
int v = vec[u][i];
if(v == fa) continue;
dp[u][2] = min(dp[u][2], dp[v][1] + dp[u][0] - dp[v][2]);
}
}
int main(){
int n;
while(scanf("%d",&n) == 1 && n != -1){
for(int i=0; i<maxn; i++){
vec[i].clear();
}
for(int i=0; i<n-1; i++){
int u,v;
scanf("%d%d",&u,&v);
vec[u].push_back(v);
vec[v].push_back(u);
}
dfs(1,-1);
printf("%d\n",min(dp[1][1], dp[1][2]));
int end;
scanf("%d",&end);
if(end == -1) break;
}
}
/*
6
1 3
2 3
3 4
4 5
4 6
0
2
1 2
-1
*/