01背包(给容量增加限制条件) 之 hdu 3466

//  [7/24/2014 Sjm]
/*
模拟一组测试数据:
2 10
5 10 5
3 5 6
1)若先选择第一组先来:
背包所用容量: 0  1  2  3  4  5  6  7  8  9  10
  第一遍循环: 0  0  0  0  0  0  0  0  0  0  5
  第二遍循环: 0  0  0  0  0  6  6  6  6  6  6
2)若先选择第二组先来:
背包所用容量: 0  1  2  3  4  5  6  7  8  9  10
  第一遍循环: 0  0  0  0  0  6  6  6  6  6  6
  第二遍循环: 0  0  0  0  0  6  6  6  6  6  11
可见选择物品的顺序会影响最后的结果。
再看方程: dp[j] = max(dp[j], dp[j - arr[i].p] + arr[i].v)
结合测试数据发现,只有保证 dp[j - arr[i].p] 最优,才能保证 dp[j] 最优,满足无后效性。
若想使 dp[j - arr[i].p] 最优,即要保证:
对于任意两组值:1) p1, q1, v1 和 2) p2, q2, v2
假设先选择1),则若想满足无后效性,
那么 j-arr[2].p >= arr[1].q,且 j-arr[1].p <= arr[2].q (否则可能出现,依赖先选2)计算的值取到更优的解)
由此推得:arr[1].q - arr[1].p <= arr[2].q - arr[2].p,得到如何去决定物品的顺序。。。
 
当然如果不想这样证明,还有另外一种理解方式:
q-p 的差值越小,在每次循环时,与基本的01背包相比,不更新的值也就越少,也就越接近基本的01背包,求出的值也就相对越大。
*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAX = 505;
int N, M;
int dp[5005];

struct node {
	int p, q, v;
};

node arr[MAX];

bool Cmp(const node &n1, const node &n2) {
	return (n1.q - n1.p < n2.q - n2.p);
}

int Solve() {
	memset(dp, 0, sizeof(dp));
	for (int i = 1; i <= N; ++i) {
		for (int j = M; j >= arr[i].q; --j) {
			dp[j] = max(dp[j], dp[j - arr[i].p] + arr[i].v);
		}
	}
	return dp[M];
}

int main()
{
	//freopen("input.txt", "r", stdin);
	while (~scanf("%d %d", &N, &M)) {
		for (int i = 1; i <= N; ++i) {
			scanf("%d %d %d", &arr[i].p, &arr[i].q, &arr[i].v);
		}
		sort(arr + 1, arr + N + 1, Cmp);
		printf("%d
", Solve());
	}
	return 0;
}
原文地址:https://www.cnblogs.com/shijianming/p/4140820.html