没有看书和题解做的一道树形DP题,思路很清晰。。只是debug上花了很久的时间才发现看错了条件。。并不是每个点都只能和一台服务器相邻,而是非服务器的点只能和一台服务器相邻。。看错了一个条件差距大了去了。。
设d[u][col][fcol]代表节点为u,颜色为col,父亲节点为fa,颜色为fcol时的最小服务器数量。col值为1代表服务器,0代表计算机,则转移方程:
d[u][1][x]:只要col为1,则每个节点既可以是服务器也可以不是;
d[u][0][1]:节点u是不服务器,fa是服务器,则u的子节点都不是服务器;
d[u][0][0]:节点u和fa都不是服务器
状态转移:dp(u,1,x)=sum{min(dp(v,0,u,1),dp(v,1,u,1))} + 1;
dp(u,0,1) = sum{dp(v,0,u,0)};
dp(u,0,0)=min{dp(u,0,1)-dp(v,0,0)+dp(v,1,x)};
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cmath>
#include<sstream>
#include<climits>
#define INF 1000000
using namespace std;
const int maxn = ; int n;
int u,v;
vector<int> g[maxn];
int ed;
int d[maxn][][]; int dp(int u,int col,int fa,int fcol)
{
if(d[u][col][fcol] > -) return d[u][col][fcol]; if(col == ){
//if(g[u].size() == 1&&g[u][0] == fa) return d[u][col][fcol] = 1;
int sum = ;
for(int i = ; i < g[u].size(); ++i){
int v = g[u][i];
if(v != fa)
sum+=min(dp(v,,u,),dp(v,,u,));
}
return d[u][col][fcol] = sum;
}
else if(fcol == &&col == ){
//if(g[u].size() == 1&&g[u][0] == fa) return d[u][col][fcol] = 0;
int sum = ;
for(int i = ; i < g[u].size(); ++i){
int v = g[u][i];
if(v != fa){
sum+=dp(v,,u,);
}
}
return d[u][col][fcol] = sum;
}
else if(fcol == &&col == )
{
//if(g[u].size() == 1&&g[u][0] == fa) return d[u][col][fcol] = INF;
int sum = dp(u,,fa,);//cout<<sum<<"***"<<endl;
int ans = INF;
for(int i = ; i < g[u].size(); ++i){
int v = g[u][i];
if(v != fa){
ans = min(ans,sum + dp(v,,u,)- dp(v,,u,));
}
}
return d[u][col][fcol] = ans;
}
} int main()
{
//freopen("in","r",stdin);
while(~scanf("%d",&n))
{
memset(d,-,sizeof(d));
for(int i = ; i <= n-; ++i)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
cout<<min(dp(,,-,),dp(,,-,))<<endl;
for(int i = ; i <= n; ++i) g[i].clear();
cin>>ed;
if(ed == -) return ;
}
}