01背包问题:POJ3624
背包问题是动态规划中的经典问题,而01背包问题是最基本的背包问题,也是最需要深刻理解的,否则何谈复杂的背包问题。
POJ3624是一道纯粹的01背包问题,在此,加入新的要求:输出放入物品的方案。
我们的数组基于这样一种假设:
totalN表示物品的种类,totalW表示背包的容量
w[i]表示第i件物品的重量,d[i]表示第i件物品的价值。
F(i,j)表示前i件物品放入容量为j的背包中,背包内物品的最大价值。
F(i,j) = max{ F(i-1,j) , F(i-1,j-w[i])+d[i] }
我们仅考虑第i件物品到底放不放进背包
第一项表示不放入背包的情况。
第二项表示放入背包的情况。
然后,我们为了获得具体的方案,每当在局部最优的方案成立时,则将path[i][j]置为1,当求的最优结果后,从最终结果开始回溯,看看在第i轮的局部最优中是否放入物品i。
此时的代码如下所示:
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
using namespace std;
#define max(a,b) a>b?a:b;
//数组要设的比给的范围稍大一些
int dp[][];
int path[][];
int w[];
int d[];
int totalN;
int totalW;
int main()
{
int i,j;
scanf("%d",&totalN);
scanf("%d",&totalW); for(i=;i<=totalN;i++)
{
scanf("%d",&w[i]);
scanf("%d",&d[i]);
} memset(dp,,sizeof(dp));
for(i=;i<=totalN;i++){
for(j=;j<=totalW;j++){
/*必不可少,需要根据上一轮状态,
而如果直接从j=w[i]开始,会使0<j<w[i]都为0,影响正确的结果。
在之后优化的1维矩阵方法中,就不会存在这种问题,
由于其逆序遍历,上一轮的结果只要不覆盖,就一直存在*/
dp[i][j] = dp[i-][j];
if(j>=w[i] && dp[i][j]<dp[i-][j-w[i]]+d[i]){
dp[i][j] =dp[i-][j-w[i]]+d[i];
path[i][j] = ;
}
}
}
printf("背包内物品的最大价值是:\n");
printf("%d\n",dp[totalN][totalW]);
i = totalN;
j = totalW;
printf("放入背包的物品是:\n");
while(i> && j>)
{
if(path[i][j] == )
{
printf("%d\n",d[i]);
j = j - w[i];
}
i = i - ;
} system("pause");
return ;
}
此时的时间复杂度是O(NW),已经无法优化,但空间复杂度可以由O(NW)下降到O(W).。
我们可以看到F(i,j)仅仅依赖于F(i-1,j)和F(i-1,j-w[i])+d[i],也就是说,我们需要依赖的上一轮的序列中的元素的坐标没有在J的右边的,此时我们就可以使用逆序遍历即可,直接应用上一轮的数据。
这样的逆序遍历还有一层意义,即每个物品只放入一次,因为所以来的两项都是没有放入过第i件物品的情况,从不依赖放入第i件物品的情况。这点需要好好的理解一下,有助于后续对完全背包问题的理解。
上代码:
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
using namespace std;
//数组要设的比给的范围稍大一些
int bag[];
int path[][];
int w[];
int d[];
int totalN;
int totalW;
int main()
{
int i,j;
scanf("%d",&totalN);
scanf("%d",&totalW); for(i=;i<=totalN;i++)
{
scanf("%d",&w[i]);
scanf("%d",&d[i]);
} memset(bag,,sizeof(bag));
for(i=;i<=totalN;i++){
for(j=totalW;j>=w[i];j--){
if(bag[j]<bag[j-w[i]]+d[i]){
bag[j] = bag[j-w[i]]+d[i];
path[i][j]=;
}
}
}
printf("背包内物品的最大价值是:\n");
printf("%d\n",bag[totalW]);
i = totalN;
j = totalW;
printf("放入背包的物品是:");
while(i> && j>)
{
if(path[i][j] == )
{
printf("%d\n",d[i]);
j = j - w[i];
}
i = i - ;
} system("pause");
return ;
}
最后如果想去AC的话,要采用第二种方案,降低空间复杂度,AC代码(折叠):
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
using namespace std;
//数组要设的比给的范围稍大一些
int bag[];
int w[];
int d[];
int totalN;
int totalW;
int main()
{
int i,j;
scanf("%d",&totalN);
scanf("%d",&totalW); for(i=;i<=totalN;i++)
{
scanf("%d",&w[i]);
scanf("%d",&d[i]);
}
memset(bag,,sizeof(bag));
for(i=;i<=totalN;i++){
for(j=totalW;j>=w[i];j--){
if(bag[j]<bag[j-w[i]]+d[i]){
bag[j] = bag[j-w[i]]+d[i];
}
}
}
printf("%d\n",bag[totalW]);
system("pause");
return ;
}
01背包问题:POJ3624的更多相关文章
- 动态规划入门-01背包问题 - poj3624
2017-08-12 18:50:13 writer:pprp 对于最基础的动态规划01背包问题,都花了我好长时间去理解: poj3624是一个最基本的01背包问题: 题意:给你N个物品,给你一个容量 ...
- poj3624 简单的01背包问题
问题描述: 总共有N种宝石供挑选,宝石i的重量为Wi,吸引力为Di,只可以用一次.Bessie最多可负担的宝石手镯总重量为M.给出N,M,Wi,Di,求M. 非常标准的01背包问题.使用了优化的一维数 ...
- 01背包问题:Charm Bracelet (POJ 3624)(外加一个常数的优化)
Charm Bracelet POJ 3624 就是一道典型的01背包问题: #include<iostream> #include<stdio.h> #include& ...
- HDU 1864最大报销额 01背包问题
B - 最大报销额 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit St ...
- HDOJ 2546饭卡(01背包问题)
http://acm.hdu.edu.cn/showproblem.php?pid=2546 Problem Description 电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额.如 ...
- YTU 2335: 0-1背包问题
2335: 0-1背包问题 时间限制: 1 Sec 内存限制: 128 MB 提交: 15 解决: 12 题目描述 试设计一个用回溯法搜索子集空间树的函数.该函数的参数包括结点可行性判定函数和上界 ...
- c语言数据结构:01背包问题-------动态规划
两天的时间都在学习动态规划:小作业(01背包问题:) 数据结构老师布置的这个小作业还真是让人伤头脑,自己实在想不出来了便去网上寻找讲解,看到一篇不错的文章: http://www.cnblogs.co ...
- HDU2602 (0-1背包问题)
N - 01背包 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Descri ...
- hdu5188 加限制的01背包问题
http://acm.hdu.edu.cn/showproblem.php? pid=5188 Problem Description As one of the most powerful brus ...
随机推荐
- UE用法
ueditor去除自动转换 ueditor在使用中发现很多问题.比如自动添加P标签,自动去除span,自动给li添加ul开始结束,自动把div转成P标签等等. 其实很多在百度上可以找到.这里总结下, ...
- Gson处理
public class GsonTools { public GsonTools(){} public static <T> T getPerson(String jsonString, ...
- 用Visual Studio调试Windows和驱动程序
由于本人能力有限,翻译不足之处敬请谅解,欢迎批评指正:sunylat@163.com Visual Studio版本:Visual Studio 2015企业版,中文环境. MSDN原文:https: ...
- 使用 Jmeter 做 Web 接口测试
接口测试概述 定义 API testing is a type of software testing that involves testing application programming in ...
- [IIS]IIS扫盲(二)
iis - IIS之Web服务器建立 第一篇 IIS之Web服务器 一.建立第一个Web站点 比如本机的IP地址为192.168.0.1,自己的网页放在D:\Wy目录下,网页的首页文件名为Inde ...
- LeetCode Implement pow(x, n).
这个题目我也没有思路,同学们可以查看这个http://www.cnblogs.com/NickyYe/p/4442867.html 下面是我改进后的代码 第一种方法: class Solution { ...
- poj 1416 (hdu 1539)Shredding Company:剪枝搜索
点击打开链接 题目大意是有一个分割机,可以把一串数字分割成若干个数字之后求和,题目输入一个数字上界和待分割的数字,让我们求出分割后数字之和在不超过给定max的情况下的最大值,并且给出分割方案,如果没有 ...
- Oracle 收缩表大小 Oracle Shrink Table --转载
从10g开始,oracle开始提供Shrink的命令,假如我们的表空间中支持自动段空间管理 (ASSM),就可以使用这个特性缩小段,即降低HWM.这里需要强调一点,10g的这个新特性,仅对ASSM表空 ...
- javascript MVC(每天有学习一点篇)
“写的不是代码,是你的思维”,经常觉得自己写的代码“皮粗肉糙”的,看到那些要么精致小巧,要么优雅大方,要么光明磊落的代码时,常常会黯然神伤外加垂涎欲滴. why?(为什么我的代码不能如此..) whe ...
- JS的join函数用法
无意中在网上看到一个关于join比for循环更有效率的说法.虽然不明白为什么,先记一笔. join函数用于数组.返回值为一个字符串.实现的效果就是将数组连成自己想要的字符串,当然是有规律可循的字符串. ...