欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

3466 ACM Proud Merchants 变形的01背包

程序员文章站 2022-04-14 21:58:02
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3466 题意:假设你有M元,已经Pi,Qi,Vi(i为角标,1Qi,时才能购买该商品,得到价值Vi,问得到的最大的价值。 思路:知道是变形的01背包问题,但是思考了很久不知道怎么解决,于是看 ......

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3466

题意:假设你有m元,已经pi,qi,vi(i为角标,1<i<n),当m>qi,时才能购买该商品,得到价值vi,问得到的最大的价值。

思路:知道是变形的01背包问题,但是思考了很久不知道怎么解决,于是看了好几种不同款式的大佬的代码和证明才看懂,如下是自己写的证明:

如果不改变,直接用01背包的话呢,就是:

for(int i=0;i<n;i++)

for(int j=v;j>=a[i].q,j--)

dp[i]=max(dp[j],dp[j-a[i].p]+a[i].v);

这个dp使用前是没有对商品排序的,就是商品的购买顺序本该对他没影响,但是在本题中购买a->b,和购买b->a,是不一样的,

假设有两组数据:

2 m

a:p1,q1,v1

b:p2,q2,v2

a->b  需要的背包容量:p1+q2

b->a  需要的背包容量:p2+q1

自然我们需要剩下背包的容量更大的方案进行购买,及如果a->b,就有:p1+q2<p2+q1 移项为 q1-p1>q2-p2,也就是说我们每次选择时都希望购买 q-p更大的商品;

但是对应我们的dp:

for(i = 0;i<n;i++)
for(j = m;j>=a[i].q;j--)
dp[j] = max(dp[j],dp[j-a[i].p]+a[i].v);

实质是:当满足j>=a[i].q时,就马上确定购买物品i,然后再用剩下的j-a[i].p去购买最大价值,i的购买顺序是先于j-a[i].p的,所以dp的顺序就希望从q-p小的先dp,

于是用sort排序,由于默认是升序,但是本题中:

sort(a,a+n)会出错,因为有a.p,a.q.a.v,a.ca,多个a,会不知道是哪一个a作为首地址,a+n作为尾地址。

于是先写下:

bool cmp(note a,note b)
{
return a.ca < b.ca;
}

sort(a,a+n,cmp)

就知道是a.ca了

代码:

 

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;


int dp[5010];

struct note
{
int p,q,v;
int ca;
} a[510];
bool cmp(note a,note b)
{
return a.ca < b.ca;
}

int main()
{
int n,m,i,j;
while(~scanf("%d%d",&n,&m))
{
for(i = 0;i<n;i++)
{
scanf("%d%d%d",&a[i].p,&a[i].q,&a[i].v);
a[i].ca = a[i].q-a[i].p;
}
sort(a,a+n,cmp);
memset(dp,0,sizeof(dp));
for(i = 0;i<n;i++)
for(j = m;j>=a[i].q;j--)
dp[j] = max(dp[j],dp[j-a[i].p]+a[i].v);
printf("%d\n",dp[m]);
}
}