HDU 1561 The more, The Better
http://acm.hdu.edu.cn/showproblem.php?pid=1561
樹形dp+有依賴的背包。==分組背包。
思路:
思路:參考《背包九講》
分組背包:將物品分成k組,每組中有若干件物品,并且這些物品兩兩互斥(既對于第 i 組物品,只能選該組物品的其中一個,或者一個也不選),求在一定的背包容量下如何選得最大值。
依賴背包:對于要選物品b,必須在選擇a的情況下才能選,這樣的背包問題稱為有依賴的背包。普通的有依賴的背包很容易轉換成分組背包來做,假如要選c必須先選a,要選b也必須先選a,若a,b,c的價值分別為Va,Vb,Vc,容量分別為Ca,Cb,Cc,則可以將這三件物品構成一個分組,假設最大容量為V,對b,c在容量為(V-Ca)(因為a必選)的條件下進行01背包,得到在這樣的容量下的最優解。其中最優解分別存在dp[0...V-Ca]+Va,把這些最優解當成新物品來用(這些新物品構成一個分組,因為這里已經包含了對b,c的所有選擇情況了,不同的選擇肯定是互斥的)。把所有依賴關系進行分組后,直接分組背包的做法。(所謂普通的分組背包,其實也就是若b依賴a,則b不能再被其他物品依賴,既不存在先選a才能選b,先選b才能選c這樣的鏈式關系。)
然而,往往存在一般情況,也就是題目給出的就是鏈式關系。若把不依賴于任何物品的物品當作根節點,那么這樣的鏈式關系可以構成一棵樹,沒被其他物品依賴的物品就是葉子。這就是基礎的樹形DP,若某節點的所有孩子都是葉子,那么這個節點跟它的孩子可以構成一個分組。
注意:len=1開始,容量為m+1。
The more, The Better
Time Limit: 6000/2000 MS (Java/Others)????Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4889????Accepted Submission(s): 2885
Problem Description ACboy很喜歡玩一種戰略游戲,在一個地圖上,有N座城堡,每座城堡都有一定的寶物,在每次游戲中ACboy允許攻克M個城堡并獲得里面的寶物。但由于地理位置原因,有些城堡不能直接攻克,要攻克這些城堡必須先攻克其他某一個特定的城堡。你能幫ACboy算出要獲得盡量多的寶物應該攻克哪M個城堡嗎? Input 每個測試實例首先包括2個整數,N,M.(1 <= M <= N <= 200);在接下來的N行里,每行包括2個整數,a,b. 在第 i 行,a 代表要攻克第 i 個城堡必須先攻克第 a 個城堡,如果 a = 0 則代表可以直接攻克第 i 個城堡。b 代表第 i 個城堡的寶物數量, b >= 0。當N = 0, M = 0輸入結束。 Output 對于每個測試實例,輸出一個整數,代表ACboy攻克M個城堡所獲得的最多寶物的數量。 Sample Input 3 2 0 1 0 2 0 3 7 4 2 2 0 1 0 4 2 1 7 1 7 6 2 2 0 0 Sample Output 5 13 注意:len=1開始,容量為m+1。 #include<iostream> #include<cstring> #include<cstdio> using namespace std; int dp[205][205],n,m,len;//dp[x][y]表示以x為根節點,選擇了j件物品 int head[205]; struct node {int now,next,val; }tree[205]; void add(int x,int y,int v) {tree[len].now=y;tree[len].val=v;tree[len].next=head[x];head[x]=len++; } void dfs(int root) {int i,j,k,son;for(i=head[root];i!=-1;i=tree[i].next){//說明有孩子,往下搜,直到搜到葉子為止son=tree[i].now;dfs(son);for(j=m+1;j>=1;j--)//背包容量為M+1,是因為多條鏈式關系,不能構成樹,加入一個根節點0,其價值為0,所以有M+1的容量。for(k=1;k<j; k++)//k<j,就是相當于V-Ca<V,a是必選的,容量為1dp[root][j] = max(dp[root][j],dp[root][j-k]+dp[son][k]+tree[i].val);//dp[to][k]是已經搜過的,是新物品} }int main() {int i,a,b;while(~scanf("%d%d",&n,&m)&n!=0&m!=0){len=1;//len=0,是根節點,一定要注意。memset(dp,0,sizeof(dp));memset(head,-1,sizeof(head));for(i=1;i<=n;i++){scanf("%d%d",&a,&b);add(a,i,b);}tree[0].val=0;dfs(0);printf("%d\n",dp[0][m+1]);}return 0; }?
轉載于:https://www.cnblogs.com/cancangood/p/3667314.html
總結
以上是生活随笔為你收集整理的HDU 1561 The more, The Better的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详解C调用lua脚本效率测试
- 下一篇: HDU 1294 Rooted Tree