標籤:style blog http color os strong io for
題目分析:
攻佔城堡所能獲得的最多寶物,但是有個限制,要想攻佔某個城堡前必須先攻佔另一個城堡
思路:
建圖,建立一個根節點為0,那麼題目就變為要想取得子節點必須先取得它的父親節點
今天為瞭解決這個問題,看了下背包九講中的有依賴的背包,刷了道模板題。
大概思路是:要想取得附件必須先取主件,主件要麼取,要麼不取,取得話要怎麼分配給附件,用01背包處理附件,然後再把每個主件分組背包
樹形的依賴主要是附件是個集合,附件還有附件。森林的概念
根據DP的思想,我們先dfs到葉,01背包操作 即可。只是每次dfs後可以攻佔的次數就減一
dp[i][j]表示以i為根攻佔j次所能獲得的最大寶物,則dp[i][1]=value[i]
這裡的dp[i][j]是必須取i的意思,只有取了i,才能取i的子節點
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#define M 10000using namespace std;struct pp{int v,w,next;}edge[M*2];int tot,root,head[M],n,m;inline void addedge(int u,int v,int w,int *h){edge[tot].v=v,edge[tot].w=w,edge[tot].next=h[u],h[u]=tot++;}int dp[210][210],vis[210],value[210];void dfs(int u,int c){ vis[u]=1; dp[u][1]=value[u]; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(vis[v]) continue; dfs(v,c-1); //剩餘所能攻佔的次數減一 for(int k=c;k>=0;--k){ //節點所能攻佔的次數 for(int j=0;j<k;++j){ //在所能攻佔的次數裡找到最優的 dp[u][k]=max(dp[u][k],dp[u][k-j]+dp[v][j]); //01背包dp[i][j]=max(dp[i][j],dp[i][j-c]+w) //這裡的w就是dp[v][j] } } }}int main(){ while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){ memset(head,-1,sizeof head); for(int i=1;i<=n;++i){ int u,w; scanf("%d%d",&u,&w); addedge(u,i,w,head); value[i]=w; } memset(dp,0,sizeof dp); memset(vis,0,sizeof vis); dfs(0,m+1); printf("%d\n",dp[0][m+1]); } return 0;}