BZOJ P4472 salesman【树形DP】【挖坑】

题目分析:

这道题一共两个问题,第一个问题求最大收益直接用树形DP求解即可,第二个问题想了很久还是无解,看了网上大神的题解仍然没有过多说明是如何判断多解的情况(也就是下面参考代码的G[]数组),想了很久也仍然没有特别理解,所以第二问先挖一个坑,来讲一讲第一个问的做法。

首先我们来考虑一下题目当中的限制次数都含义,我们会如何经过一个点呢?一个就是从父亲节点下来,还有就是从儿子节点上来,显然对于一个点最多从父亲节点下来1次,于是我们很容易得到下面的一个结论:

Limit[I]表示I号节点最多经过Limit次,即以I号节点为根的子树最多经过Limit-1棵子树。

有了这个结论之后,再结合树形DP定状态的套路可以得到如下的状态:

DP[I]表示在以I为根节点的子树中走不超过Limit[I]-1棵子树的最大收益(此处的子树不包括I号点本身)

既然已经定好了状态,那么状态转移也很容易想到了:

DP[I]应该由大到小加上Limit[I]-1棵子树的答案(数量满足以及大于等于0的条件)

这样我们就只需要在代码当中枚举出I号点的儿子节点然后记录排序即可。

这就是第一问的做法了(第二问挖坑),参考代码如下:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int Max=1e5+5;
int G[Max],DP[Max];
int N,Tmp[Max],Value[Max],Limit[Max];
int Cnt,To[Max<<1],Next[Max<<1],Head[Max];
inline int Read(){
    int X=0;char CH=getchar();bool F=0;
    while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}
    while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}
    return F?-X:X;
}
inline void Write(int X){
    if(X<0)X=-X,putchar('-');
    if(X>9)Write(X/10);
    putchar(X%10+48);
}
bool Cmp(int X,int Y){
    return DP[X]>DP[Y];
}
void Insert(int X,int Y){
    To[++Cnt]=Y;Next[Cnt]=Head[X];Head[X]=Cnt;
}
void Tree_DP(int X,int Fx){
    int I,J,K;
    DP[X]=Value[X];
    for(I=Head[X];I;I=Next[I]){
        int Y=To[I];
        if(Y!=Fx){
            Tree_DP(Y,X);
        }
    }int Num=0;
    for(I=Head[X];I;I=Next[I]){
        int Y=To[I];
        if(Y!=Fx){
            Tmp[++Num]=Y;
        }
    }sort(Tmp+1,Tmp+1+Num,Cmp);
    int Tot=0;
    while(Tot<min(Limit[X]-1,Num)){
        if(DP[Tmp[Tot+1]]<0){
            break;
        }Tot++;
        DP[X]+=DP[Tmp[Tot]];G[X]|=G[Tmp[Tot]];
    }
    if(Tot<Num&&Tot>0&&DP[Tmp[Tot]]==DP[Tmp[Tot+1]]||DP[Tmp[Tot]]==0&&Tot>0){
        G[X]=1;
    }
}
int main(){
    int I,J,K;
    N=Read();
    for(I=2;I<=N;I++){
        Value[I]=Read();
    }
    for(I=2;I<=N;I++){
        Limit[I]=Read();
    }Limit[1]=N+1;
    for(I=1;I<N;I++){
        int X=Read(),Y=Read();
        Insert(X,Y);Insert(Y,X);
    }Tree_DP(1,0);
    Write(DP[1]);putchar('\n');
    if(G[1]!=0){
        puts("solution is not unique");
    } else {
        puts("solution is unique");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/80719307