树形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思路。有些时候我们可以固定某个位置,然后以其为中心对其他各个位置求相应的值,并最终得到所要答案

原创粉丝点击