树形dp
来源:互联网 发布:java线程池和队列 编辑:程序博客网 时间:2024/04/29 02:20
Cell Phone Network
/*
树形DP
d[i][0]为不取i并且以i为根节点的树都被覆盖需要的数目
d[i][1]为取i并且以i为根节点的树都被覆盖需要的数目
d[i][2]为不取i并且以i为根节点的树根结点i没有被覆盖,其他点都被覆盖需要的数目
*/
#include <iostream>
#include <vector>
using namespace std;
#define MAX 10000
vector<int> v[10005];
int d[10005][3];
int mmin(int x,int y){return x>y?y:x;}
int mmax(int x,int y){return x<y?y:x;}
void dfs(int x,int p)
{
int i;
for(i=0;i<v[x].size();i++)
{
if(v[x][i]!=p)
dfs(v[x][i],x);
}
if(v[x].size()==1&&v[x][0]==p)
{
d[x][0]=1;
d[x][1]=1;
d[x][2]=0;
return;
}
int m=MAX;
for(i=0;i<v[x].size();i++)
{
int k=v[x][i];
if(k!=p)
{
int big=mmax(d[k][0],d[k][1]);
int small=mmin(d[k][0],d[k][1]);
d[x][0]+=small;
d[x][1]+=mmin(small,d[k][2]);
if(big-small<m)
m=big-small;
if(d[k][0]>=d[k][1])
m=0;
d[x][2]+=small;
}
}
d[x][1]+=1;
d[x][0]+=m;
}
int main()
{
int n,i,a,b;
while(scanf("%d",&n)!=EOF)
{
for(i=1;i<=n;i++)
v[i].clear();
for(i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
v[a].push_back(b);
v[b].push_back(a);
}
memset(d,0,sizeof(d));
dfs(1,0);
printf("%d\n",mmin(d[1][0],d[1][1]));
}
return 0;
}
此题提供了一种较好的扩展的dp思路。有些时候我们可以固定某个位置,然后以其为中心对其他各个位置求相应的值,并最终得到所要答案