失蹤人口回歸系列 這個標題是不是看起來很厲害呢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,已修復,詳見注釋