01背包问题基础

背包问题

一 背包问题的一般形式

例题

例:张三去抢劫时,带了一个容积为8的背包,等他闯进店里,发现店里有四件物品,如何装他的背包可使获利最大。

itemsspacevalue
电脑(1)31500
吉他(2)51000
平板(3)2500
音响(4)1200

分析:

张三在拿取某物品时,会出现两种状态:
1.空间不足,这个物品无法拿取
2.空间足够,可以拿取也可以不拿取(拿取不一定是最优解,因为你只拿三个物品不一定就比拿四个物品便宜)

状态一:

 bag[i][j]=bag[i-1][j];
 // i指的是第i个物品,j指的是背包的容量,bag[i][j]指的是在j空间下,对前i个物品进行选择(不一定拿)得到的最大价值

状态二:

bag[i][j]=max(bag[i-1][j],bag[i-1][j-space[i]]+value[i])
// 比较在j空间下选择到i-1个物品和在j空间下选择了第i个物品的价值,判断方案中是否包应该含有物品i

根据这两个状态转移方程我们可以得到下面的表格

i\j12345678
100150015001500150015001500
200015001500150015001500
30500150015002000200020002500
4200500150017002000220025002500

发现最大值为2500,用代码表示表格如下

   for (int i=1; i<=m; i++) {
        for (int j=1; j<=t; j++) {
            if(j<tim[i]) bag[i][j]=bag[i-1][j];
            else bag[i][j]=max(bag[i-1][j],bag[i-1][j-tim[i]]+value[i]);
        }
    }

完整代码如下:

#include <stdio.h>
int value[200];
int space[200];
int bag[1010][1010];
int max(int x,int y)
{
    if(x>y) return x;
    return y;
}
int main() {
    int t,m;
    scanf("%d%d",&t,&m);
    for (int i=1; i<=m; i++) {
        scanf("%d%d",&space[i],&value[i]);
    }
    for (int i=1; i<=m; i++) {
        for (int j=1; j<=t; j++) {
            if(j<space[i]) bag[i][j]=bag[i-1][j];
            else bag[i][j]=max(bag[i-1][j],bag[i-1][j-space[i]]+value[i]);
        }
    }
    printf("\n%d",bag[m][t]);
    return 0;
}

遍历每一种投资可能,从bag[1][1]到最终的bag[4][8],在每一种空间下,判断是否包含某个物品,最终累加得到最终的最优解。

二.回溯解的组成

毕竟还得知道到底怎么抢…
此时只需要倒退回去,判断是否拿取

bag[i-1][j]<bag[i-1][j-space[i]]+value[i]
// 如果前者小于后者,则说明是拿取了第i个物品

从最上面的物品,总空间开始,向下递推,打印解

int tcopy =t
for (int i=m; i>0; i--) {
        if(bag[i-1][tcopy]<bag[i-1][tcopy-space[i]]+value[i]){ printf("%d ",i);tcopy-=space[i];}
    }

大家如果有不清楚的地方欢迎在评论区留言,我会为大家解答😘

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值