题意:有n (n≤10000) 台机器形成树形结构。要求在其中一些机器上安装服务器,使得每台不是服务器的计算机恰好和一台服务器计算机相邻。求服务器的最少数量。(本段摘自《算法竞赛入门经典(第2版)》
分析:
树形DP。
dp[u][0]
表示u是服务器,则每个子结点可以是服务器也可以不是。
dp[u][1]
表示u不是服务器,但u的父亲是服务器,这意味着u的所有子结点都不是服务器。
dp[u][2]
表示u和u的父亲都不是服务器。这意味着u恰好有一个儿子是服务器。
dp[u][0]=sum(min(dp[v][0],dp[v][1]))+1,dp[u][1]=sum(dp[v][2]),dp[u][2]=min(dp[u][1]−dp[v][2]+dp[v][0])
。
代码:
#include <iostream>
#include <algorithm>
#include <fstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>
#include <map>
using namespace std;
const int maxn = 10000 + 5, INF = 10000000 + 5;
int n, x, y;
int dp[maxn][3];
vector< int > sons[maxn];
int DP(int u, int k, int f)
{
if (dp[u][k] >= 0)
return dp[u][k];
if (k == 0)
dp[u][k] = 1;
else if (k == 1)
dp[u][k] = 0;
else
dp[u][k] = INF;
for (int i = 0; i < sons[u].size(); ++i)
{
int v = sons[u][i];
if (v == f)
continue;
if (k == 0)
dp[u][k] += min(DP(v, 0, u), DP(v, 1, u));
else if (k == 1)
dp[u][k] += DP(v, 2, u);
else
dp[u][k] = min(dp[u][k], DP(u, 1, f) - DP(v, 2, u) + DP(v, 0, u));
if (dp[u][k] > INF)
dp[u][k] = INF;
}
return dp[u][k];
}
int main()
{
while (~scanf("%d", &n))
{
memset(dp, -1, sizeof(dp));
for (int i = 1; i <= n; ++i)
sons[i].clear();
for (int i = 0; i < n - 1; ++i)
{
scanf("%d%d", &x, &y);
sons[x].push_back(y);
sons[y].push_back(x);
}
printf("%d\n", min(DP(1, 0, -1), DP(1, 2, -1)));
scanf("%d", &x);
}
return 0;
}