01背包问题:

01背包问题:

1.递归思想

0- 1 背包问题如果采用递归算法来描述则非常清楚明白, 它的算法根本思想是假设用布尔函数
knap( s, n) 表示n
件物品放入可容质量为s 的背包中是否有解( 当knap 函数的值为真时

说明问题有解,其值为假时无解) . 我们可以通过输入s 和n 的值, 根据它们的值可分为以下几种情况讨论:

( 1) 当s= 0时可知问题有解, 即函数knap( s, n) 的值为true; ( 2) 当s< 0 时这时不可能,

所以函数值为false; ( 3) 当输入的s> 0 且n< 1 时即总物品的件数不足1, 这时函数值为false,

只有s> 0 且n \1 时才符合实际情况,这时又分为两种情况: ( 1) 选择的一组物体中不包括Wn

则knap( s, n) 的解就是knap( s, n- 1) 的解. ( 2) 选择的一组物体中包括Wn 则knap( s, n)
的解

就是knap( s- Wn, n- 1) 的解. 这样一组Wn 的值就是问题的最佳解. 这样就将规模为n 的问题转化为

规模为n- 1 的问题. 综上所述0- 1 背包问题的递归函数定义为:
knap( s, n) =∕true, s=
0
            
︳false, s<
0
            
︳false, s> 0 且n<
1
             
\knap( s, n- 1) 或knap( s- Wn, n- 1) , s> 0 且n>= 1
采用此法求解0- 1
背包问题的时间复杂度为O( n) . 上述算法对于所有物品中的某几件恰能装满背包
时能准确求出最佳解.
但一般情况是对于某一些物品无论怎么装都不能装满背包, 必须要按背包的最大
容量来装. 如物品件数为4, 其质量分别为: 10, 2, 5,
4, 背包的容量为20, 则这四件物品无论怎么放都不
能恰好装满背包, 但应能最大限度装, 即必须装下10, 5, 4 这三件物品,
这样就能得到最大质量19. 对于
这种装不满的背包它的解决办法是这样的: 按所有物品的组合质量最大的方法装背包,
如果还装不满,
则我们可以考虑剩余空间能否装下所有物品中最小的那件, 如果连最小的都装不下了则说明这样得到
的解是最佳解, 问题解决.
这样我们必须先找出所有n 件物品中质量最小的那件( 它的质量为Min) , 但
是为了问题的解决我们不能增加运算次数太多,
并且必须运用上述递归函数. 那么我们可通过修改s 的
值即背包的容量, 从背包容量s 中减去k( 它的值是从0 到Min- 1
之间的一个整数值) , 再调用递归函
数. 当k= 0 时即能装满背包, 其它值也能保证背包能最大限度装满, 这样所有问题都解决了.

①例题一:

简单背包问题
Time Limit:  
1000MS       Memory Limit:  
65535KB 
Submissions:  
2217       Accepted:   408

Description 
设有一个背包可以放入的物品重量为S,现有n件物品,重量分别是w1,w2,w3,…wn。 
问能否从这n件物品中选择若干件放入背包中,使得放入的重量之和正好为S。 
如果有满足条件的选择,则此背包有解,否则此背包问题无解。
  
Input输入数据有多行,包括放入的物品重量为s,物品的件数n,以及每件物品的重量(输入数据均为正整数)
多组测试数据。 
Output对于每个测试实例,若满足条件则输出“YES”,若不满足则输出“NO“ 
Sample
Input
20 5
1 3 5 7 9
Sample Output
YES

# include<stdio.h>
# include<string.h>
int
date[1005];
int f(int w,int s)
{
if(w==0) return
1;//正好
if(w<0||w>0 &&s==0) return 0;

if(f(w-date[s],s-1)) return 1;//退出来再选下一个
return
f(w,s-1);//选择下一个
}

int main()
{
int i,Weight,n;
while(scanf("%d
%d",&Weight,&n)!=EOF)
{

memset(date,0,sizeof(date));
for(i=1;i<=n;i++)

scanf("%d",&date[i]);
if(f(Weight,n))

printf("YES\n");
else printf("NO\n");
}
return
0;
}
}

2.贪心算法

用贪心法设计算法的特点是一步一步地进行,根据某个优化测度(可能是目标函数,也可能不是目标函数),每一步上都要保证能获得局部最优解。

每一步只考虑一个数据,它的选取应满足局部优化条件。若下一个数据与部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,

直到把所有数据枚举完,或者不能再添加为止。


#include<iostream>
#include<algorithm>
using namespace std;
struct good//表示物品的结构体
{
double p;//价值
double w;//重量
double r;//价值与重量的比
};
good a[2000];
bool bigger(good a,good b)
{
if(a.r==b.r)return a.w<b.w;
else return a.r>b.r;
}
int main()
{
double s,value,m;
int i,n;
cin>>m>>n;//读入包的容量和物品个数
for (i=0;i<n;i++)
{
cin>>a[i].w>>a[i].p;
a[i].r=a[i].p/a[i].w;
}
sort(a,a+n,bigger);//调用sort排序函数,按照价值与重量比和质量排序贪心
s=0;//包内现存货品的重量
value=0;//包内现存货品总价值
for (i=0;i<n;i++)
if(s+a[i].w<=m)
{
value+=a[i].p;
s+=a[i].w;
}
cout<<"The total value is "<<value<<endl;//输出结果
return 0;
}

但仔细想就会发现有个很大的问题,
10 4
5 10
8 16
5 5
10
10
就会出问题,被装进去就不会拿出来,可见“拿来主义”行不通!
接下来介绍另一种算法:动规

3.动态规划【正解】

有N件物品和一个容量为V的背包。第i件物品的体积是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
状态转移方程:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} 
这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的 
伪码:
  for
i=1..N 
   for
v=V..0 
    f[v]=max{f[v],f[v-c[i]]+w[i]};
如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,
价值为f[i-1][v];
如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,
此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

②例题二:
采药

Time Limit:   1000MS      
Memory Limit:   65535KB 
Submissions:  
155       Accepted:   50

Description辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?  
Input输入的第一行有两个整数T(1
<= T <= 1000)和M(1 <= M <=
100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。 
Output输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。 
Sample
Input
70 3
71 100
69 1
1 2
Sample Output
3

#include<iostream>
# include<cstring>
# define
max(a,b) a>b?a:b
using namespace std;
int main()
{

int dp[101][1001],m,T,w[101],val[101],i,j;

cin>>T>>m;
for(i=1;i<=m;i++)

cin>>w[i]>>val[i];
memset(dp,0,sizeof(dp));

for(i=1;i<=m;i++)
for(j=0;j<=T;j++)//j相当于上面说的V-c[i]

{
if(j>=w[i])

dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+val[i]);//放还是不放的选择
else
dp[i][j]=dp[i-1][j];
}

cout<<dp[m][T]<<endl;
return 0;
}

这里就测试一下,
10 4
5 10
8 16
5 5
10 10

01背包问题:,布布扣,bubuko.com

时间: 2024-12-20 08:13:18

01背包问题:的相关文章

动态规划之01背包问题(最易理解的讲解)

01背包问题,是用来介绍动态规划算法最经典的例子,网上关于01背包问题的讲解也很多,我写这篇文章力争做到用最简单的方式,最少的公式把01背包问题讲解透彻. 01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ),  f[i-1,j] } f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值. Pi表示第i件物品的价值. 决策:为了背包中物品总价值最大化,第 i件物品应该放入背包中吗 ? 题目描述: 有编号分别为a,b

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

动态规划 - 0-1背包问题

0-1背包问题描述如下: 有一个容量为V的背包,和一些物品.这些物品分别有两个属性,体积w和价值v,每种物品只有一个.要求用这个背包装下价值尽可能多的物品,求该最大价值,背包可以不被装满.因为最优解中,每个物品都有两种可能的情况,即在背包中或者不存在(背 包中有0个该物品或者 1个),所以我们把这个问题称为0-1背包问题. 用dp[i][j]表示前i个物品在总体积不超过j的情况下,放到背包里的最大价值.由此可以推出状态转移方程: dp[0][j] = 0; dp[i][j] = max{dp[i

01背包问题的动态规划算法

01背包问题我最初学会的解法是回溯法,第一反应并不是用动态规划算法去解答.原因是学习动态规划算法的时候,矩阵连乘.最长公共子串等问题很容易将问题离散化成规模不同的子问题,比较好理解,而对于01背包问题则不容易想到将背包容量离散化抽象出子问题,从情感上先入为主也误以为动态规划算法不是解决01背包问题的好方法,实际上并不是这样的.另外,动态规划算法不对子问题进行重复计算,但是要自底向上将所有子问题都计算一遍,直到计算出最终问题的结果也就是我们要的答案,有点像爬山的感觉. 问题描述:给定n种物品和一背

ACM 01背包问题1

Description Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave … The bone collector had a big bag with a volume of V ,and

算法学习 - 01背包问题(动态规划C++)

动态规划 01背包 问题描述 求解思路 代码实现 放入哪些物品 代码 动态规划 我在上一篇博客里已经讲了一点动态规划了,传送门:算法学习 - 动态规划(DP问题)(C++) 这里说一下,遇到动态规划应该如何去想,才能找到解决办法. 最主要的其实是要找状态转移的方程,例如上一篇博客里面,找的就是当前两条生产线的第i个station的最短时间和上一时刻的时间关系. minTime(station[1][i]) = minTime(station[1][i-1] + time[i], station[

【算法导论】0-1背包问题

一.0-1背包问题描述: 已知:小偷在店里偷东西,小偷只带了一个最大承重为W的背包,商店里有N件商品,第i件商品的重量是weight[i],价钱是value[i]. 限制:每种商品只有一件,可以选择拿或者不拿,不能分割,不能只拿一件商品的一部分(所以叫做0-1,0即不拿,1则整个拿走,且一种商品有且只有一件可供拿走) 问题:在不超过背包最大承重的情况下,最多能拿走多少钱的商品. 算导上与0-1背包问题对应的是分数背包问题,分数背包问题中的物品是可以取一部分的,就是说可以拆分的,不像0-1背包中,

0-1背包问题(动态规划)

<span style="font-size:18px;">#include<iostream> #include<vector> #include<iterator> #include<algorithm> #include<string> using namespace std; /* *0-1背包问题(动态规划) */ vector<vector<int>> values;//valu

01背包问题

01背包问题详解 题目 有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使价值总和最大. 基本思路 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放. 用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值.则其状态转移方程便是: f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} 这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的.所以有必

动态规划法——求解0-1背包问题

问题描述 0-1背包问题与背包问题(贪心法--背包问题)最大的不同就是背包问题的子问题彼此之间没有联系,所以只要找出解决方法,然后用贪心算法,取得局部最优解就ok了,但是0-1背包问题更复杂,因为物品不可再分,导致了子问题之间是有联系的. 问题分析 1,刻画背包问题最优解的结构 2,数学描述 伪代码解读 当上段代码运算完成之后,对于C[i,w]的表: 然后根据上面构造的表,求最优解: 小结 动态规划法在判断是否含有第i个物品时,通过判断C[I,w]是否等于C[i-1,w]来得出是否含有第i个物品