其实如果只有pi和vi,这就是很简单的01背包的问题,但是现在多了一个约束条件qi,这让这题截然不同。
让我最困惑的是例程中的第二个输入数据,如果我先买第二个商品,消耗了3元,剩下7元,那我就不可以买第一个商品了,只能买第三个,这样得出的结果是9,显然不是最优解,所以这个题目中购买商品需要有一个顺序,但是这个顺序我实在是一脸懵逼,只好靠别人的题解了。
思路大致是:
1,先不考虑顺序,这道题最大的麻烦是qi,我们所建立的01背包中,范围不再是pi - max了,而是qi - max,因为要有qi的钱才有资格去判断。
2,如果有pi = qi的情况,如果全是这种情况,这就是超级原始的01背包问题了,01背包中各个商品的加入原本是无序的。
3,终于要烧脑了,顺序怎么去想?只要想办法确定顺序,接下来就像无序那样建立01背包就行了。
人生的大起大落实在是太爽了,所以我们直接列举十分极限的数据来看看
依旧是只有10块钱,接下来商品:
1 10 1
1 10 10
1 1 1
10 10 10
后面两组情况是满足pi=qi的,理论上是无序的嘛,看前两组,第二组肯定是最好的,1元就能买到价格为10元的商品,当然这个前提是qi<=m,但是01背包中我们最后只要那个dp[n][m]这个角的数字,就是说第二组数据和第四组数据是相同的结果,所以我们再分析分析这两组数据。
这两组数据肯定是有不同的,不同在哪里呢?那就是pi的值。如果我们是比较第三组和第四组,pi也是不同的,其实要管qi吗?我们前面说这两组可以无序排序,在大前提下,他们的qi都是小于m的,所以这直接就是01背包是吧,在01背包里面if(j>=item[i].weight) max(dp[j - item[i].weight] + item[i].value, dp[j]); 这个if判断就代表了他是weight到最大值m之间的循环。如果这个weight直接都大于m了,这个循环就直接跳出一层了。所以题目例程1当qi=15那种情况也要读入,只是我们会在后面跳出罢了。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int dp[5005];
struct trade
{
int pi,qi,vi;
}goods[505];
int cmp(const void *a,const void *b)
{
return ((*(trade *)a).qi-(*(trade *)a).pi)-((*(trade *)b).qi-(*(trade *)b).pi);
}
int main()
{
int n,m,i,j;
while(scanf("%d %d", &n, &m) != EOF)
{
for(i = 0; i < n; i++)
scanf("%d %d %d", &goods[i].pi, &goods[i].qi, &goods[i].vi);
qsort(goods, n , sizeof(goods[0]), cmp);
for(j = 0; j <= m; j++)
{
dp[j] = 0;
}
for(i = 0; i < n; i++)
{
for(j = m; j >= goods[i].qi; j--)
{
if(dp[j - goods[i].pi] + goods[i].vi > dp[j])
dp[j] = dp[j - goods[i].pi] + goods[i].vi;
}
}
printf("%d\n", dp[m]);
}
}