您的位置:首页 > 其它

hiho 7 完全背包

2015-11-06 21:23 239 查看

问题描述

有N种物品, 每种物品价值为vi, 花费为ci, 每种物品可以购买多个,现在有M单位的钱,要求能够买到的物品价值最大值。

解法

类似01背包,这里只是改变了物品可以购买多个,如果还按01背包的解法,dp(i, x)表示用x钱买前i种物品,可以得到的最大值,状态转移公式为:

dp(i,x)=max(dp(i−1,x−k∗ci)+k∗vi)|0≤k≤x/ci

k=0 表示不买第i种物品,k>0表示买k件第i种物品。

可以发现这样求解时存在重复的,

很容易得到下面的公式:

dp(i,x−ci)+vi=max(dp(i−1,x−ci−k∗ci)+k∗vi)+vi

0≤k≤(x−ci)/ci

=>

dp(i,x−ci)+vi=max(dp(i−1,x−ci−k∗ci)+k∗vi+vi)

0≤k≤(x−ci)/ci

=>

dp(i,x−ci)+vi=max(dp(i−1,x−(k+1)∗ci)+(k+1)∗vi)

0≤k≤(x−ci)/ci

dp(i,x−ci)+vi=max(dp(i−1,x−k′∗ci)+k′∗vi)

1≤k′≤x/ci

因此:

dp(i,x)=max(dp(i−1,x),dp(i,x−ci)+vi)

01背包时对于dp(i, 0) ~dp(i, M) 我们是从后往前求的,

现在只需要换过来从前往后求就可以了。

代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
enum {maxn = 100000+5};
int dp[maxn];
#define OJ
int main()
{
#ifndef OJ
freopen("in.txt", "r", stdin);
#endif // OJ
int n, m;
scanf("%d %d", &n, &m);
memset(dp, 0, sizeof(int)*(m+1));
int need, value;
while(n--)
{
scanf("%d %d", &need, &value);
for (int i=need; i<= m; i++)
dp[i] = max(dp[i], dp[i-need]+ value);
}
printf("%d\n", dp[m]);
return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp