程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> hdu-1561 The more, The Better (樹形dp入門,有依賴的背包問題

hdu-1561 The more, The Better (樹形dp入門,有依賴的背包問題

編輯:C++入門知識


The more, The Better

Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4954 Accepted Submission(s): 2922


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

解題思路:

以樹來存儲各城堡之間的依賴關系。

首先說狀態表示,dp[i][j]表示在以i為根節點的子樹上攻破j個城堡可達到的最大收益。

為方便表示,以0號節點為總的根節點。

接下來使用‘背包九講’中‘有依賴的背包問題’一節的思路來做。

‘有依賴的背包’是指要選某些物品,必須先選某件物品。這與本題恰好符合。

設j1號、j2號。。。jn號這n件物品依賴i號物品,那麼可以將這n+1個物品歸為一組,那麼這n+1個物品可能有以下的取法:


只取第i號;


取第i號和第j1號;

取第i號和第j1、j2號;

。。。

取第i號和第j1、j2。。。jn號;


取第i號和第j2號;

取第i號和第j2、j3號;

。。。

。。。

取第i號和第jn號;


可是這種取法效率很低,很多多余情況。可以用01背包的方法來進行優化,即對這n+1種物品進行一次01背包,即可得出所有需要考慮的情況(具體參考‘背包九講’)

不過因為i的第k個子節點jk也可能被jk的子節點所依賴,所以要通過dfs先把jk的工作做好再來處理i


代碼:

#include
#include
#include
#include
#include

using namespace std;

vector	map[205];
int val[205],dp[205][205];
int n,m;
//dp[i][j]:以第i個節點為起始,攻擊j次的最大獲益

inline int bet(int x,int y)
{
	if(x>y)	return x;
	return y;
}
void dfs(int bg,int c)
{
	int size=map[bg].size();
	dp[bg][1]=val[bg];//只攻擊該節點
	
	for(int i=0;i1)	dfs(map[bg][i],c-1);
		//若未到最後,則繼續向下深搜,先算好將來所需的數據

		for(int j=c;j>1;--j)//當背包容量為c時,j=1時為只選bg
		{
			for(int k=0;k<=j-1;++k)
			{
				//攻擊了第i個子節點下的k個節點,那麼還剩下j-k次機會攻擊其余的
				dp[bg][j]=bet(dp[bg][j],dp[bg][j-k]+dp[map[bg][i]][k]);
			}
		}
	}
}

int main()
{
	while(cin>>n>>m)
	{
		if(n==0&&m==0)	break;

		memset(val,0,sizeof(val));
		memset(dp,0,sizeof(dp));
		for(int i=0;i<=n;++i)	map[i].clear();
		int a,b;
		for(int i=1;i<=n;++i)
		{
			scanf("%d%d",&a,&b);
			map[a].push_back(i);
			val[i]=b;
		}

		dfs(0,m+1);//從‘0’開始
		cout<


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved