递归法解决多重背包问题

多重背包问题同样是01背包问题的变种,同样可以通过修改01背包部分代码来求解。

方法一:修改递归函数,根据题目新的限制条件——使用次数扩充状态参数个数,将同一个物品选用的次数同样作为参数传递到栈空间中,同时也对原状态数组扩充一位,防止记忆化搜索时状态溢出。

扩充状态数组:state[volume][worth]\rightarrow state[volume][worth][times]

改变递归函数:

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;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Andy_Xie007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值