洛谷1217 有线电视网 树上dp

状态非常好想,dp[i][j]表示以i为根的子树选j个叶子所能产生的最大价值。
这是个树上背包,方程好想,不太好写。

for(int k=sz[x];k;k--)
for(int j=1;j<=sz[v];j++)
    dp[x][k]=max(dp[x][k],dp[x][k-j]+dp[v][j]-b[i].d);

一定要注意for的顺序,k从大到小for。
然后放在树上……

#include
#include
#define maxn 3005
using namespace std;
struct E{
    int to,nxt,d;
}b[maxn];
int fst[maxn],tot;
void build(int f,int t,int d)
{
    b[++tot]=(E){t,fst[f],d};
    fst[f]=tot;
}
int val[maxn];
int sz[maxn];
int n,m;
void dfs(int x)
{
    if(x>n-m)
    {sz[x]=1;return ;}
    for(int i=fst[x];i;i=b[i].nxt)
    {
        int v=b[i].to;
        dfs(v);sz[x]+=sz[v];
    }
}
int dp[maxn][maxn];
int a[maxn];
void f(int x)
{
    dp[x][0]=0;
    if(x>n-m)
    {
        dp[x][1]=val[x];
        return ;
    }
    for(int i=fst[x];i;i=b[i].nxt)
    {
        int v=b[i].to;
        f(v);
        for(int k=sz[x];k;k--)
        for(int j=1;j<=sz[v];j++)
            dp[x][k]=max(dp[x][k],dp[x][k-j]+dp[v][j]-b[i].d);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,u,d;
    for(int i=1;i<=n-m;i++)
    {
        scanf("%d",&x);
        for(int j=1;j<=x;j++)
        {
            scanf("%d%d",&u,&d);
            build(i,u,d);
        }
    }
    for(int i=1;i<=n;i++)
    for(int j=0;j<=n;j++)
        dp[i][j]=-1e9;
    for(int i=n-m+1;i<=n;i++)
        scanf("%d",&val[i]);
    int p=m,t;
    dfs(1);f(1);
    for(t=p;t>=0;t--)
        if(dp[1][t]>=0) break;
    printf("%d",t);
}

你可能感兴趣的:(===DP及优化===,DP)