题意:2392和3466都是在有01背包的同时也有额外的限制,2392是木板搭天梯,每种木板有一个高度限制,木板的任何地方都不能超出这个高度,而3466是买东西,但是买某一件东西是时,要求拥有的钱多余某个数(买之前的钱)。
题解:这两个问题类似,都是在结果中本来没有顺序的差别,但是因为有了新的限制,有了使用物品先后顺序的差别。考虑最优的结果,一定是容易购买的在后面才买,要求比较高的在前面才买,并且dp背包本身就是枚举,那么只需先对物品进行排序然后在正常dp+限制就好了。关键是排序的方法:应该用两个物品特殊情况来考虑写cmp函数,比如买东西,1和2,先买1再买2可以,但是先买2再买1就不行,把这两个等式写出来,就能写出排序的依据。同理,木板搭天梯也是这样,只是那个比较简单,直接按照限制排序就好。
重点:当有一些限制使得不同购买顺序对结果不一样时,利用两个物品比较来搞出cmp的标准,排序后dp。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const int maxn = 5000 + 100;
int dp[maxn], n, tot;
struct info
{
int p, q, v;
};
info a[maxn];
void getDp()
{
memset(dp, -1, sizeof(dp));
dp[0] = 0;
REP_D(i, 1, n)
{
for(int j = tot;j >= 0;j--)
{
if(j >= a[i].p&&(tot - (j-a[i].p) )>=a[i].q&&dp[j-a[i].p]!=-1&&dp[j-a[i].p]+a[i].v>dp[j])//dp方程,只是多了一个额外限制,其实通过这个限制也能
{//推出排序标准
dp[j] = dp[j-a[i].p]+a[i].v;
}
}
}
}
bool cmp(info a, info b)
{
return a.q - a.p > b.q - b.p;//核心关键,排序标准。
}
void solve()
{
sort(a + 1, a+1+n, cmp);
getDp();
int ans = 0;
REP_D(i, 0, tot)
{
ans = max(ans, dp[i]);
}
printf("%d\n", ans);
}
int main()
{
// freopen("2Bin.txt", "r", stdin);
//freopen("3Bout.txt", "w", stdout);
while(scanf("%d%d", &n, &tot) != EOF)
{
REP_D(i, 1, n)
{
scanf("%d%d%d", &a[i].p, &a[i].q, &a[i].v);
}
solve();
}
return 0;
}