一類有依賴的樹形背包dp方法


失蹤人口回歸系列 這個標題是不是看起來很厲害呢233

給一道例題:有一個樹,每一個節點代表一個物品,每個物品有重量和價值,每個物品必須先選父親才能選自己。求給定重量內最大價值。

這題的思路十分的厲害。我們把樹的dfs序建出來,對於dfs序上每一個點,我們考慮如果自己選那么自己子樹內就可以選,否則只有在這棵子樹外面才可以選。

那么我們記f[i][j]為dfs序中第i個點及以后的dfs序大小為j的聯通塊的最大權值,所以我們可以得出f[i][j]=max(f[i+1][j-w[i]]+v[st[i]],f[i+sz[st[i]]][j])類似這樣。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
using namespace std;
//w=weight v=value
#define SZ 5004
int n,m,fa[SZ],w[SZ],v[SZ],fc[SZ],nc[SZ],md[SZ],siz[SZ],dp[SZ][SZ];
int st[SZ],t=0,dl[SZ];
void ass(int x) {int f=fa[x]; if(f) nc[x]=fc[f], fc[f]=x;}
void dfs(int p)
{
    siz[p]=1; st[p]=++t; dl[t]=p;
    for(int c=fc[p];c;c=nc[c])
    {
        dfs(c); siz[p]+=siz[c];
    }
}
#define FO(x) {freopen(#x".in","r",stdin); freopen(#x".out","w",stdout);}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d%d",fa+i,w+i,v+i), ass(i);
    dfs(1);
    for(int p=0;p<=m;p++) dp[n+1][p]=dp[n+2][p]=-1000000000;
    dp[n+1][0]=0; //原來這里忘了寫 
    for(int i=n;i>=1;i--)
    {
        int x=dl[i];
        for(int p=0;p<=m;p++)
        {
            if(p<w[x]) dp[i][p]=max(dp[i+siz[x]][p],0);
            else dp[i][p]=max(max(dp[i+siz[x]][p],dp[i+1][p-w[x]]+v[x]),0);
        }
    }
    printf("%d\n",dp[1][m]);
}

UPD:發現一個bug,已修復,詳見注釋


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM