(树形dp & 有依赖的背包)hdu 1011 Starship Troopers & hdu 1561 The more, The Better

题目
hdu1011

题意:
一张图有 n 个结点,有 m 个士兵,每个士兵可以消灭 20 个虫子,结点1是入口,通过边可以走的任意一个结点并消耗结点上的虫子对应的士兵获得这个结点对应的脑子,当没有士兵后就不能继续往下走。

另一种解释:
有一个m个容量的背包,有 n 个物品,每个物品的一个代价u 和一个价值v,有些物品如果拿走需要对应的物品也被拿走,求m个容量最大的价值。(即背包9讲中的有依赖的背包)

思路:
每个结点p 的代价为c [ p ],价值为v [ p ]
从结点1 dfs 下去,在每个结点p 中,dp [ p ] [ i ] 表示在结点p 容量为i 的最大的价值,一开始dp [ p ] [ 0 ] → dp [ p ] [ m ] 都为0
首先把结点p 放到背包里,使得dp [ p ] [ c[ p ] ] → dp [ p ] [ m ] 为v[ p ]
对于结点p 的每个子节点s :
d p [ p ] [ i ] = m a x ( v [ p ] , max ⁡ k = 1 i − c [ p ] d p [ p ] [ i − k ] + d p [ s ] [ k ] ) ) ( i ≥ c [ p ] ) dp[p][i]=max(v[p],\max_{k=1}^{i-c[p]} dp[p][i-k] + dp[s][k]))(i≥c[p]) dp[p][i]=max(v[p],k=1maxic[p]dp[p][ik]+dp[s][k]))ic[p]

ps:如果m = 0时最大的价值为0

题目
hdu1561

题意:
hdu 1011的换皮

思路:
思路与hdu1011一样,但是有一点要注意的是:结点0的代价为0,其它结点的代价为1

hdu 1011代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector> 
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
using namespace std;
const int MAXN = 110;
int dp[MAXN][MAXN], c[MAXN], v[MAXN];
bool vis[MAXN];
vector<int> tree[MAXN];
int n, m;
void dfs(int p){
    
    
	vis[p] = true;
	int len = tree[p].size();
	for (int i = m; i >= c[p]; i--)
		dp[p][i] = v[p];
	for (int i = 0, s; i < len; i++){
    
    
		s = tree[p][i];
		if (!vis[s]){
    
    
			dfs(s);
			for (int j = m; j > c[p]; j--)
				for (int k = 1; k <= j - c[p]; k++)
					dp[p][j] = max(dp[p][j], dp[p][j-k] + dp[s][k]);
		} 
	}
}
int main(){
    
    
	while (~scanf("%d%d", &n, &m) && !(n == -1 && m == -1)){
    
    
		for (int i = 1; i <= n; i++){
    
    
			scanf("%d%d", &c[i], &v[i]);
			c[i] = (c[i] % 20 != 0) ? c[i] / 20 + 1 : c[i] / 20;
		}
		for (int i = 1; i <= n; i++)
			tree[i].clear();
		for (int i = 1, p, s; i < n; i++){
    
    
			scanf("%d%d", &p, &s);
			tree[p].push_back(s);
			tree[s].push_back(p);
		}
		if (m == 0){
    
    
			printf("0\n");
			continue;
		}
		memset(vis, false, sizeof(vis));
		memset(dp, 0, sizeof(dp));
		dfs(1);
		printf("%d\n", dp[1][m]);
	}
	return 0;
}

hdu 1561代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector> 
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
using namespace std;
const int MAXN = 210;
int dp[MAXN][MAXN], v[MAXN];
vector<int> tree[MAXN];
int n, m;
void dfs(int p){
    
    
	int len = tree[p].size();
	int root = (p == 0) ? 0 : 1;  //结点0的代价为0,其它结点的代价为1
	for (int i = m; i > 0; i--)
		dp[p][i] = v[p];
	for (int i = 0, s; i < len; i++){
    
    
		s = tree[p][i];
		dfs(s);
		for (int j = m; j > 0; j--)
			for (int k = 1; k <= j - root; k++)  //结点0的代价为0,其它结点的代价为1
				dp[p][j] = max(dp[p][j], dp[p][j-k] + dp[s][k]);
	}
}
int main(){
    
    
	while (~scanf("%d%d", &n, &m) && !(n == 0 && m == 0)){
    
    
		for (int i = 0; i <= n; i++)
			tree[i].clear();
		for (int i = 1, p; i <= n; i++){
    
    
			scanf("%d%d", &p, &v[i]);
			tree[p].push_back(i);
		}
		if (m == 0){
    
    
			printf("0\n");
			continue;
		}
		memset(dp, 0, sizeof(dp));
		dfs(0);
		printf("%d\n", dp[0][m]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ymxyld/article/details/113813483