ACM竞赛学习整理开篇之01背包问题

ACM竞赛学习整理开篇之01背包问题。

最近,偶然的一次机会让我关注信息奥赛的一些内容。发现其中的内容很有趣,是学习编程的一条很好的路径,又能很好地将数学和编程联系到一起。在csdn里看到了不少同好也在学习ACM竞赛。于是,决定通过csdn这个平台来记录,我的ACM学习之路。

背包问题:

背包问题已经研究了一个多世纪,早期的作品可追溯到1897年 [1] 数学家托比亚斯·丹齐格(Tobias Dantzig,1884-1956)的早期作品 [2] ,并指的是包装你最有价值或有用的物品而不会超载你的行李的常见问题。

背包问题的应用:

1998年的石溪布鲁克大学算法库的研究表明,在75个算法问题中,背包问题是第18个最受欢迎,第4个最需要解决的问题(前三为后kd树,后缀树和bin包装问题)。
背包问题出现在各种领域的现实世界的决策过程中,例如寻找最少浪费的方式来削减原材料, [4] 选择投资和投资组合, [5] 选择资产支持资产证券化 [6] ,和生成密钥为Merkle-Hellman [7] 和其他背包密码系统。

在ACM竞赛中设计的背包问题有:

在这里插入图片描述

先了解下3种简单的背包概念:

0-1背包 (ZeroOnePack): 有N件物品和一个容量为V的背包。每种物品均只有一件 第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
完全背包(CompletePack): 有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
多重背包 (MultiplePack): 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用, 每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。*

比较三个题概念,会发现不同点在于每种背包的数量,01背包是每种只有一件,完全背包是每种无限件,而多重背包是每种有限件。

**

01 背包

1、OJ 例题
【例题】
有n个物品,编号为i的物品的重量为w[i],价值为c[i],现在要从这些物品中选一些物品装到一个容量为m的背包中,使得背包内物体在总重量不超过m的前提下价值尽量大。
【输入】
第1行:两个整数,n(物品数量,n≤3500)和m(背包容量,m≤12880)。
第2…n+1行::每行二个整数w[i],c[i],表示每个物品的重量和价值。
【输出】
仅一行,一个数,表示最大总价值。
【输入样例】
4 6
1 4
2 6
3 12
2 7
【输出样例】
23

2、 解题思路:

用动态规划的思路,阶段就是“物品的件数”,状态就是“背包剩下的容量”,那么很显然f [ i , v ] 就设为从前 i 件物品中选择放入容量为 v 的背包最大的价值。那么状态转移方程为:

 f[i][v]=max{ f[i-1][v],f[i-1][v-w[i]]+val[i] }。

把这个过程理解下:在前i件物品放进容量v的背包时,

它有两种情况:

第一种是第i件不放进去,这时所得价值为:f[i-1][v]

第二种是第i件放进去,这时所得价值为:f[i-1][v-w[i]]+val[i]

(第二种是什么意思?就是如果第i件放进去,那么在容量v-w[i]里就要放进前i-1件物品)

最后比较第一种与第二种所得价值的大小,哪种相对大,f[i][v]的值就是哪种。

(这是基础,要理解!)

3、 代码求解:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 1001
#define MOD 2520
#define E 1e-12
using namespace std;
int m,n;
int w[N],c[N],f[N];

void ZeroOnePack(int cost,int weight)
{
    for(int v=m;v>=weight;v--)
    {
    	  f[v]=max(f[v],f[v-weight]+cost);
        
        cout<<"f["<<v<<"]"<<"="<<f[v]<<"    ";
    }
      cout<<endl;
}
 
int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;i++)
        cin>>w[i]>>c[i];
		 
    cout<<endl;
    
      for(int i=1;i<=n;i++)
        ZeroOnePack(c[i],w[i]);
        
    cout<<"max="<<f[m]<<endl;
   
    return 0;
}

4、结果输出

在这里插入图片描述
5、反思总结

背包问题是贪心算法的实例,可以根据动态规划解题步骤来实现

(问题抽象化、建立模型、寻找约束条件、判断是否满足最优性原理、找大问题与小问题的递推关系式、填表、寻找解组成)找出01背包问题的最优解以及解组成,然后编写代码实现。

回顾01背包的定义:
在这里插入图片描述

PS:学习的心得比较难写,我将代码放到了C-free开发环境中试验了下,然后把计算的结果打印在了屏幕上,然后草稿纸上将其步骤再简单画了画,最后在网上查找了相关的内容来帮助理解,以上内容,基本上还是复制粘贴,等后续实际问题再操练吧。
这里有杭电OJ上的一道例题供大家参考:

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2602

代码:http://www.wutianqi.com/?p=533

参考文档:

1、https://blog.csdn.net/weixin_41162823/article/details/87878853背包问题-笔记整理

2、https://blog.csdn.net/qq_37767455/article/details/9908667801背包问题 图解+详细解析

3、http://www.wutianqi.com/blog/539.html背包之01背包、完全背包、多重背包详解

4、https://blog.csdn.net/chanmufeng/article/details/82955730彻底理解0-1背包问题

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值