【树DP+背包】求树的最小点覆盖的点个数

来源:互联网 发布:淘宝神笔怎么保存模板 编辑:程序博客网 时间:2024/04/28 19:59
http://blog.sina.com.cn/s/blog_48f85e1d0100qd3k.html

这个是dfs中用dp,当前点状态取决于其子节点的状态,具体转换如下:
i,0表示以i为根的子树被覆盖,i点未放置的最小数目
i,1表示以i为根的子树被覆盖,i点放置的最小数目
i,2表示i的子树被覆盖,i点未被覆盖的最小数目
之所以有这三种状态,是因为,一个点被覆盖的方式有三种:该点被放置,该点的子节点放置,该点的父节点放置

i,0 =sigm(min(j,0;j,1;j,2)且保证至少一个j,1被取到
i,1 =sigm(min(j,0;j,1;j,2)
i,2 =sigmj,0



#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int vd[10001];
int n,m;
int arm[20001][2];//记录边
int index[10001];//记录i节点的邻接边在arm里的索引
int num[10001][3];//记录以i为根的树,选改节点与不选该节点的最小数目
int cmp(const void *a,const void *b){
    int *x=(int *)a;
    int *y=(int *)b;
    return x[0]-y[0];
}
int min(int a,int b){
    if(a<b)
        return a;
    return b;
}
void init(){
    int i,j;
    scanf("%d",&n);
    for(i=0;i<n-1;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        arm[2*i][0]=a;
        arm[2*i][1]=b;
        arm[2*i+1][0]=b;
        arm[2*i+1][1]=a;
    }
    m=2*n-2;
    memset(vd,0,sizeof(vd));
    memset(index,-1,sizeof(index));
    qsort(arm,m,sizeof(int)*2,cmp);
    for(i=0,j=0;i<m;i++){
        if(i==0||arm[i][0]!=arm[i-1][0]){
            index[arm[i][0]]=i;
        }
    }
}
void dfs(int v){
    int i,j,k,t;
    vd[v]=1;
    int isleaf=1;
    int sum1=0;
    int sum0=0;
    int sum2=0;
    int reduce=99999999;
    if(index[v]!=-1){
        for(i=index[v];arm[i][0]==v;i++){
            if(vd[arm[i][1]]==0){
                dfs(arm[i][1]);
                isleaf=0;
                sum1+=min(min(num[arm[i][1]][0],num[arm[i][1]][1]),num[arm[i][1]][2]);
                sum2+=num[arm[i][1]][0];
                //统计sum0=================================================reduce 始终>=0

                sum0+=min(num[arm[i][1]][0],num[arm[i][1]][1]);//先取最小的和
                if(num[arm[i][1]][1]-num[arm[i][1]][0]<reduce){//求需要在sum0上添加的最小值
                    if(num[arm[i][1]][1]-num[arm[i][1]][0]>=0)//小于当前最小值且非负,更新之
                        reduce=num[arm[i][1]][1]-num[arm[i][1]][0];
                    else//取到=1时的了,不用reduce了
                        reduce=0;
                }

                //==========================================================

            }
        }
    }
    if(isleaf){
        num[v][1]=1;
        num[v][0]=1;
        num[v][2]=0;
    }else{
        num[v][1]=1+sum1;
        num[v][0]=sum0+reduce;
        num[v][2]=sum2;
    }
}
int main(){
    int r;
    init();
    dfs(1);
    r=min(num[1][0],num[1][1]);
    printf("%d\n",r);
    scanf("%d",&r);
    return 0;
}
0 0
原创粉丝点击