递归法解决完全背包问题

本文介绍了如何通过修改01背包问题的递归函数来解决完全背包问题,包括两种方法:一是调整状态转移方程,允许物品多次选取;二是通过复制物品列表并调整体积和价值来转化为01背包问题。最后给出了C++代码示例。
摘要由CSDN通过智能技术生成

完全背包问题作为01背包问题的升级版,我们可以通过修改01背包递归函数来求解完全背包问题

题目链接:3. 完全背包问题 - AcWing题库

方法一:改变递归函数的状态转移方程

在原状态转移方程中,每个物品只选取一次导致决策时无论是选还是不选都要将物品下标数+1,下一次对列表中下一个物品做决策。由于在完全背包中物品可以随意取用,我们如果选择某物品,不必将物品下标+1,因为下一次还可能再选。修改部分如下:

refuse = dfs(index+1, vol_l);
if(vol_l >= goods[index].volume)
	choose = dfs(index, vol_l-goods[index].volume)+goods[index].worth;

方法二:修改物品列表

如果我们在读取物品时,在列表中循环插入K次(k*goods[i].volume < V)物品,其中第 j 个物品(1<j<=k)的体积和价值分别是原来的 j 倍,那么就可以将问题转换为拥有新物品列表的01背包问题,直接沿用原来01背包的递归函数即可。如果进一步采用二进制优化,新物品列表中只需增加1,2,4,8,...,2^n倍体积/价值的物品,这些物品选或不选的组合一共可以排列出选择1到2^(n+1)-1次物品的情况。当然在选用次数并非2^(n+1)-1次时会出现越界的情况,也不用考虑,因为确定的容积大小可以将越界情况排除。

#include <algorithm>

using namespace std;

struct goods
{
    int volume;
    int worth;
};

int N, V;
int state[10001][1010];
goods lst[10000];

int dfs(int code, int vol_l)
{
    int jump, stay = 0;
    if(state[code][vol_l] != -1)
        return state[code][vol_l];


    if(vol_l < 0 || code == N)
        state[code][vol_l] = 0;
    else
    {
        jump = dfs(code+1, vol_l);
        if(vol_l >= lst[code].volume)
            stay = dfs(code, vol_l-lst[code].volume)+lst[code].worth;
        
        state[code][vol_l] = max(jump, stay);
    }   
    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);

    for(int i = 0; i < N; i++)
    {
        scanf("%d %d", &lst[i].volume, &lst[i].worth);
        int add_i = 0;
        for(int j = 1; 2*lst[i+j-1].volume <= V; j++)
        {
            lst[i+j].volume = lst[i+j-1].volume*2;
            lst[i+j].worth = lst[i+j-1].worth*2;
            add_i++;
        }
        i += add_i;
        N += add_i;
    }    
    
    printf("%d", dfs(0, V));
    return 0;
}
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Andy_Xie007

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

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

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

打赏作者

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

抵扣说明:

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

余额充值