【洛谷P1273】有线电视网

有线电视网

题目链接

树形DP,分组背包

dp[u][i][j]表示以u为根的子树,前i个子树中选j个用户的最大收益.

dp[u][size[u]][0]=0;

dp[u][i][j]=max(dp[u][i][j],dp[u][i-1][j-k]+dp[v][size[v]][k]-w[u][v]);

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 3010
int n,m,dp[N][N],val[N];
struct NODE{
    int to,w,next;
} e[N];
int Head[N],num;
inline void add(int x,int y,int w){
    e[++num].to=y;
    e[num].w=w;
    e[num].next=Head[x];
    Head[x]=num;
}
inline int read(){
    int x=0; char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
    return x;
}
int dfs(int u){
    dp[u][0]=0;
    if(u>n-m){
        dp[u][1]=val[u];
        return 1;
    }
    int sum=0;
    for(int i=Head[u];i;i=e[i].next){
        int v=e[i].to;
        int sz=dfs(v);
        for(int j=sum;j>=0;j--)
         for(int k=1;k<=sz;k++)
          dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]-e[i].w);
        sum+=sz;
    }
    return sum+1;
}
int main()
{
    memset(dp,~0x3f,sizeof(dp));
    n=read(); m=read();
    int snum,y,w;
    for(int i=1;i<=n-m;i++){
        snum=read();
        while(snum--){
            y=read(); w=read();
            add(i,y,w);
        }
    }
    for(int i=n-m+1;i<=n;i++)
     val[i]=read();
    dfs(1);
    int ans=0;
    for(ans=m;ans>=1;ans--)
     if(dp[1][ans]>=0) break;
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-08-03 18:45  yjk  阅读(116)  评论(0编辑  收藏  举报