题目大意
规定W的上限为m,要求在满足W的前提下,使选择的物品D之和最大,每件物品只能拿一次。
思路分析
这是一道不要求完全取尽“0-1背包”的模板题。
知识归纳
一、完全取尽 or 不完全取尽
完全取尽:
/*INF: 当要求最小值时,INF为最大的正整数——0x7fffffff;
当要求最大值时,INF为最小的负整数——0xffffffff;*/
void init()
{
dp[0] = 0;
for(int v=1; v<=V; v++)
{
dp[v] = INF;
}
}
不完全取尽:
void init()
{
for(int v=0; v<=V; v++)
{
dp[v] = 0;
}
}
二、0-1背包 or 完全背包 or 多重背包
0-1背包:(任意物品只能拿一次)
for(int i=0; i<n; i++)
{
for(int v=V; v>=w[i]; v--)
{
dp[v] = max(dp[v], dp[v-w[i]]+c[i]);
}
}
完全背包:(任意物品可以拿任意次)
for(int i=0; i<n; i++)
{
for(int v=w[i]; v<=V; v++)
{
dp[v] = max(dp[v], dp[v-w[i]]+c[i]);
}
}
多重背包:(任意物品可以拿k次)
思路:将k件物品拆分成多件,再按0-1背包问题解决。
int cnt = 0;
for(int i==0; i<n; i++)
{
int c, w, k;
int num = 1;
while(k-num > 0) // 对数字k进行拆分
{
k -= num;
w[++cnt] = w*num;
c[cnt] = c*num;
num *= 2;
}
w[++cnt] = w*k;
c[cnt] = c*k;
}
for(int i=0; i<cnt; i++)
{
for(int v=V; v>=w[i]; v--)
{
dp[v] = max(dp[v], dp[v-w[i]]+c[i]);
}
}
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 3500;
const int maxv = 13000;
int dp[maxv], W[maxn], D[maxn];
int main()
{
// freopen("input.txt", "r", stdin);
int n, m;
scanf("%d %d", &n, &m);
for(int i=0; i<n; i++)
{
scanf("%d %d", &W[i], &D[i]);
}
for(int v=0; v<=m; v++)
{
dp[v] = 0;
}
for(int i=0; i<n; i++)
{
for(int v=m; v>=W[i]; v--)
{
dp[v] = max(dp[v], dp[v-W[i]]+D[i]);
}
}
int max_ = 0;
for(int v=0; v<=m; v++)
{
if(dp[v] > max_)
{
max_ = dp[v];
}
}
printf("%d\n", max_);
// fclose(stdin);
return 0;
}