多重背包问题同样是01背包问题的变种,同样可以通过修改01背包部分代码来求解。
方法一:修改递归函数,根据题目新的限制条件——使用次数扩充状态参数个数,将同一个物品选用的次数同样作为参数传递到栈空间中,同时也对原状态数组扩充一位,防止记忆化搜索时状态溢出。
扩充状态数组:
改变递归函数:
int dfs(int code, int times, int vol_l)
{
int jump, stay = 0;
if(state[code][times][vol_l] != -1)
return state[code][times][vol_l];
if(vol_l < 0 || code == N || times > lst[code].num)
state[code][times][vol_l] = 0;
else
{
jump = dfs(code+1, 0, vol_l);
if(vol_l >= lst[code].volume && lst[code].num > times)
stay = dfs(code, times+1, vol_l-lst[code].volume)+lst[code].worth;
state[code][times][vol_l] = max(jump_c, stay);
}
return state[code][times][vol_l];
}
#include <algorithm>
using namespace std;
struct goods
{
int volume;
int worth;
int num;
};
int N, V;
int state[101][101][101];
goods lst[101];
int dfs(int code, int times, int vol_l)
{
int jump, stay = 0;
if(state[code][times][vol_l] != -1)
return state[code][times][vol_l];
if(vol_l < 0 || code == N || times > lst[code].num)
state[code][times][vol_l] = 0;
else
{
jump = dfs(code+1, 0, vol_l);
if(vol_l >= lst[code].volume && lst[code].num > times)
stay = dfs(code, times+1, vol_l-lst[code].volume)+lst[code].worth;
state[code][times][vol_l] = max(jump_c, stay);
}
return state[code][times][vol_l];
}
int main()
{
for(int i = 0; i < 101; i++)
for(int j = 0; j < 101; j++)
for(int t = 0; t < 101; t++)
state[i][j][t] = -1;
scanf("%d %d", &N, &V);
for(int i = 0; i < N; i++)
scanf("%d %d %d", &lst[i].volume, &lst[i].worth, &lst[i].num);
printf("%d", dfs(0, 0, V));
return 0;
}
方法二:修改物品列表,仿照完全背包问题方法二对物品列表进行二次幂插入,且最大插入次数严格小于等于规定次数。
定义二次幂插入函数:
int binary_group[10] = {1,2,4,8,16,32,64,128,256,512};
void bi_divide(int input, int* out)
{
int i = 0;
for(; input-binary_group[i] >= 0; i++)
{
input -= binary_group[i];
out[i] = binary_group[i];
}
out[i] = input;
out[++i] = 0;
}
在main函数中调用物品插入函数:
int main()
{
for(int i = 0; i < 10001; i++)
for(int j = 0; j < 1010; j++)
state[i][j] = -1;
scanf("%d %d", &N, &V);
for(int i = 0; i < N; i++)
{
scanf("%d %d %d", &lst[i].volume, &lst[i].worth, &lst[i].num);
lst[i].num = min(lst[i].num, V/lst[i].volume);
int add_i = 0;
int ans[10];
bi_divide(lst[i].num, ans);
for(int j = 1; ans[j] != 0; j++)
{
lst[i+j].volume = ans[j]*lst[i].volume;
lst[i+j].worth = ans[j]*lst[i].worth;
add_i++;
}
i += add_i;
N += add_i;
}
printf("%d", dfs(0, V));
return 0;
}
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
struct goods
{
int volume;
int worth;
int num;
};
int binary_group[10] = {1,2,4,8,16,32,64,128,256,512};
void bi_divide(int input, int* out)
{
int i = 0;
for(; input-binary_group[i] >= 0; i++)
{
input -= binary_group[i];
out[i] = binary_group[i];
}
out[i] = input;
out[++i] = 0;
}
int N, V;
int state[10001][1010];
goods lst[10001];
int dfs(int code, int vol_l)
{
int refuse, choose;
if(state[code][vol_l] != -1)
{
//cout << "[" << code << "," << vol_l << "]: " << state[code][vol_l] << endl;
return state[code][vol_l];
}
if(vol_l <= 0 || code == N)
{
state[code][vol_l] = 0;
}
else
{
refuse = dfs(code+1, vol_l);
if(vol_l >= lst[code].volume)
{
choose = dfs(code+1, vol_l-lst[code].volume)+lst[code].worth;
//jump_r = dfs(code+1, vol_l-lst[code].volume)+lst[code].worth;
}
else
{
choose = 0;
//jump_r = 0;
}
state[code][vol_l] = max(choose, refuse);
}
//cout << "[" << code << "," << vol_l << "]: " << state[code][vol_l] << endl;
return state[code][vol_l];
}
int main()
{
for(int i = 0; i < 10001; i++)
for(int j = 0; j < 1010; j++)
state[i][j] = -1;
scanf("%d %d", &N, &V);
//int add_t = 0;
for(int i = 0; i < N; i++)
{
scanf("%d %d %d", &lst[i].volume, &lst[i].worth, &lst[i].num);
lst[i].num = min(lst[i].num, V/lst[i].volume);
int add_i = 0;
int ans[10];
bi_divide(lst[i].num, ans);
for(int j = 1; ans[j] != 0; j++)
{
lst[i+j].volume = ans[j]*lst[i].volume;
lst[i+j].worth = ans[j]*lst[i].worth;
add_i++;
}
/*
for(int j = 1; pow(2, j+1)-1 < lst[i].num; j++)
{
lst[i+j].volume = lst[i+j-1].volume*2;
lst[i+j].worth = lst[i+j-1].worth*2;
//add_t++;
add_i++;
}
*/
i += add_i;
N += add_i;
}
//N += add_t;
printf("%d", dfs(0, V));
return 0;
}