洛谷 P2279 [HNOI2003]消防局的设立

来源:互联网 发布:积分系统数据库设计 编辑:程序博客网 时间:2024/05/20 08:26

P2279 [HNOI2003]消防局的设立

法一:

某贪心方法(摘自洛谷题解):一般的,对于深度最大的结点u,选择u的k级祖先是最划算的(意思是说这个题目的2改成了k我们都是可以做的,至于这个结论,详见刘汝佳的《***入门经典》(蓝书P35),还有一个例题,不过和本题不一样)

法二:

//树形dp/*状态的设计:f[i][0]: 表示选了自己以后...f[i][1]: 表示选了儿子以后...f[i][2]: 表示选了孙子以后...——上面用来表示这个点被覆盖了的状态,下面为这个点没有被覆盖的状态f[i][3]: 表示自己不一定被覆盖,但是儿子一定全部被覆盖时...f[i][4]: 表示自己和儿子都不一定被覆盖,但是孙子一定全部都被覆盖时......=>最少的消防局数 i表示当前点,j表示所有有从i开始的边指向的点f[i][0]=Σmin(f[j][0..4])+1f[i][1]=min(f[k][0]+Σ(j!=k)min(f[j][0..3]))//k表示j中任何一个点,min(f[j][0..3])是由于没有选i、j点,而选了k点,因此j点能被覆盖,但如果要是j的子结点被覆盖,则需要0-3情况来满足//min(f[k][0]..)是由于可能是任意一个儿子结点被选f[i][2]=min(f[k][1]+Σ(j!=k)min(f[j][0..2])//可能是任意一个儿子结点的子节点被选//由于没有选i、j、k点,j点没有被覆盖,要是它被覆盖则需要0-2情况//举例:min(f[j][0..3])表示min(f[j][0],f[j][1],f[j][2],f[j][3])f[i][3]=Σmin(f[j][0..2])//所有的min都是对0..x生效,Σ对j生效f[i][4]=Σmin(f[j][0..3])简化: f[i][1]=min(Σmin(f[j][0..3])+f[k][0]-min(f[k][0..3]))=min(f[k][0]-min(f[k][0..3]))+Σmin(f[j][0..3])f[i][2]=min(Σmin(f[j][0..2])+f[k][1]-min(f[k][0..2]))=min(f[k][1]-min(f[k][0..2]))+Σmin(f[j][0..2])可以由此想到预处理令p[j][p]=min(f[j][0..p])(p>=2) (并非答案,只是方便计算)则f[i][0]=Σp[j][4]+1f[i][1]=Σp[j][3]+min(f[k][0]-p[k][3])f[i][2]=Σp[j][2]+min(f[k][1]-p[k][2])f[i][3]=Σp[j][2]f[i][4]=Σp[j][3]则f[i][1]=f[i][4]+min(f[k][0]-p[k][3])f[i][2]=f[i][3]+min(f[k][1]-p[k][2])实际上,不用另开p数组,直接在f中存储即可,后面会直接覆盖掉*/ //类似于最小支配集(在树中选出一些点,使得没有选出的点都与选出的点直接相连,要求选的点尽可能少)#include<cstdio>#include<algorithm>using namespace std;struct Edge{    int to,next;}edge[2100];int node[1100],edge_num,n;int f[1100][5];void make(int x,int y){    edge[++edge_num].to=y;    edge[edge_num].next=node[x];    node[x]=edge_num;}void dfs(int x){    int k=node[x],i,j,y,t1=0x3f3f3f3f,t2=0x3f3f3f3f;//优化版本     f[x][0]=1;    while(k!=0)    {        y=edge[k].to;        dfs(y);        f[x][0]+=f[y][4];        f[x][3]+=f[y][2];        f[x][4]+=f[y][3];        t1=min(t1,f[y][0]-f[y][3]);        t2=min(t2,f[y][1]-f[y][2]);        k=edge[k].next;    }    f[x][1]=f[x][4]+t1;    f[x][2]=min(min(f[x][0],f[x][1]),t2+f[x][3]);    f[x][3]=min(f[x][2],f[x][3]);    f[x][4]=min(f[x][3],f[x][4]);//    int k=node[x],i,j,y;//    while(k!=0)//    {//        y=edge[k].to;//        dfs(y);//        for(i=2;i<=4;i++)//            for(j=0;j<i;j++)//                f[y][i]=min(f[y][i],f[y][j]);//        f[x][0]+=f[y][4];//        f[x][3]+=f[y][2];//        f[x][4]+=f[y][3];//        k=edge[k].next;//    }//    f[x][0]++;//    k=node[x];//    f[x][1]=0x3f3f3f3f;f[x][2]=0x3f3f3f3f;//    while(k!=0)//    {//        y=edge[k].to;//        f[x][1]=min(f[x][1],f[y][0]-f[y][3]);//        f[x][2]=min(f[x][2],f[y][1]-f[y][2]);//        k=edge[k].next;//    }//    f[x][1]+=f[x][4];//    f[x][2]+=f[x][3];}int main(){    int i,t;    scanf("%d",&n);    for(i=2;i<=n;i++)    {        scanf("%d",&t);        make(t,i);    }    dfs(1);    printf("%d",f[1][2]); //此时f[1][2]已经是min(f[1][0..2])了    return 0;}

原创粉丝点击