洛谷P1273 有限电视网题解

本题是树形dp+分组背包问题

根据本题的条件,我们自然可以设计二维dp状态 f[i][j],显然第一维表示的是以i为根节点的树,那么考虑第二维

第二维有两种可能,一种是总价值,一种是总人数,我们可以想到控制价值并不好做,因为价值可以很大,导致数组开不起来,还有就是价值可能为负,所以我们控制第二维是以i为根节点,疏通j人的最大价值,只需要价值大于0,就满足题意。

值得一提的是我们使用了滚动数组优化,其实本来状态应该是三维,我们省略了枚举子节点的维,只需要在枚举人数的时候,倒序枚举即可。

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=3010;
int f[3010][3010];
int h[N],e[N],ne[N],w[N];
int n,m;
int va[N];
int cnt;
void add(int a,int b,int c){
    e[cnt]=b,w[cnt]=c,ne[cnt]=h[a],h[a]=cnt++;
} 
int dfs(int u){
    if(u>n-m){
        f[u][1]=va[u];
        return 1;
    }
    int i,j,k,t;
    int sum=0;
    for(i=h[u];i!=-1;i=ne[i]){
        int tmp=e[i];
        j=dfs(tmp);
        sum+=j;
        for(t=sum;t>0;t--){
            for(k=1;k<=j;k++){
                if(t>=k)
                f[u][t]=max(f[u][t],f[u][t-k]+f[tmp][k]-w[i]);
            }
        }
        
    }
    return sum;
}
int main(){
    cin>>n>>m;
    memset(h,-1,sizeof h);
    memset(f,-0x3f,sizeof f);
    int i;
    for(i=1;i<=n-m;i++){
        int si=0;
        cin>>si;
        int j,k;
        for(j=1;j<=si;j++){
            int v;
            cin>>v>>k;
            add(i,v,k);
        }
    }
    for(i=n-m+1;i<=n;i++){
        cin>>va[i];
    }
    for(i=1;i<=n;i++){
        f[i][0]=0;
    }    
    dfs(1);
    for(i=m;i>=1;i--){
        if(f[1][i]>=0){
            cout<endl;
            break;
        }
    }
    return 0;
}
View Code

 

你可能感兴趣的:(洛谷P1273 有限电视网题解)