0-1背包问题求解方法综述
![0-1背包问题求解方法综述](https://img.360docs.net/imgb0/1km66g3gbbxji74yis7blu37d4e9zpr4-01.webp)
![0-1背包问题求解方法综述](https://img.360docs.net/imgb0/1km66g3gbbxji74yis7blu37d4e9zpr4-72.webp)
算法分析与设计大作业
实验题目:0-1背包问题求解方法综述组员:
班级:
指导老师:
0-1背包问题求解方法综述
【摘要】:0-1背包问题是一个经典的NP-hard组合优化问题,现实
生活中的很多问题都可以以它为模型。本文首先对背包问题做了阐
述,然后用蛮力解法、动态规划算法、贪心算法和回溯解法对背包问
题进行求解,分析了0-1背包问题的数学模型,刻划了最优解的结构特
征,建立了求最优值的递归关系式。最后对四种算法从不同角度进行
了对比和总结。
【关键词】:0-1背包问题;蛮力解法;动态规划算法;贪心算法;回溯解法。
0.引言
0-1背包问题是指给定n个物品,每个物品均有自己的价值vi和重量
wi(i=1,2,…,n),再给定一个背包,其容量为W。要求从n个物品中选出一部分物
品装入背包,这部分物品的重量之和不超过背包的容量,且价值之和最大。单个物
品要么装入,要么不装入。很多问题都可以抽象成该问题模型,如配载问题、物资
调运[1]问题等,因此研究该问题具有较高的实际应用价值。目前,解决0-1背包问
题的方法有很多,主要有动态规划法、回溯法、分支限界法、遗传算法、粒子群
算法、人工鱼群算法、蚁群算法、模拟退火算法、蜂群算法、禁忌搜索算法等。
其中动态规划、回溯法、分支限界法时间复杂性比较高,计算智能算法可能出现
局部收敛,不一定能找出问题的最优解。文中在动态规划法的基础上进行了改进,
提出一种求解0-1背包问题的算法,该算法每一次执行总能得到问题的最优解,是确定性算法,算法的时间复杂性最坏可能为O(2n)。 1.0-1背包问题描述
0-1背包问题(KP01)是一个著名的组合优化问题。它应用在许多实际领域,如项目选择、资源分布、投资决策等。背包问题得名于如何选择最合适的物品放置于给定背包中。本文主要研究背包问题中最基础的0/1背包问题的一些解决方法。
为解决背包问题,大量学者在过去的几十年中提出了很多解决方法。解决背包问题的算法有最优算法和启发式算法[2],最优算法包括穷举法、动态规划法、分支定界法、图论法等,启发式算法包括贪心算法、遗传算法、蚁群算法、粒子算法等一些智能算法。
0-1背包问题一般描述为:给定n 种物品和一个背包。物品i 的重量是w(i),其价值为v(i),背包的容量为c 。问应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大?
在选择装入背包的物品时,对每种物品i 只有两种选择,即装入背包或不装入背包。不能将物品i 装入背包多次,也不能只装入部分的物品i 。因此,该问题称为0-1背包问题。
此问题的形式化描述是,给定n i v w c i i ≤≤>>>1000,,,,要求找出一个n 元0-1向量n i x x x x i n ≤≤∈1}1,0{21,),,,,( ,使得c
x w i i i ≤∑=n
1
,而且i
n
i i x v ∑=1
达到最大。
数学模型:∑=n
i i i x v 1max
约束条件:
c
x
w
i
i
i
≤
∑
=
n
1
,n
i
x
i
≤
≤
∈1},1,0{
2.0-1背包问题的求解算法
2.1蛮力算法(brute force method)
2.1.1基本思想:
对于有n种可选物品的0/1背包问题,其解空间由长度为n的0-1向量组成,可用子集数表示。在搜索解空间树时,深度优先遍历,搜索每一个结点,无论是否可能产生最优解,都遍历至叶子结点,记录每次得到的装入总价值,然后记录遍历过的最大价值。
2.1.2代码实现:
#include
#include
using namespace std;
#define N 100 //最多可能物体数
struct goods //物品结构体
{
int sign; //物品序号
int w; //物品重量
int p; //物品价值
}a[N];
bool m(goods a,goods b)
{
return (a.p/a.w)>(b.p/b.w);
}
int max(int a,int b)
{
return a
}
int n,C,bestP=0,cp=0,cw=0;
int X[N],cx[N];
/*蛮力法求解0/1背包问题*/
int Force(int i)
{
if(i>n-1){
if(bestP for (int k=0;k bestP=cp; } return bestP; } cw=cw+a[i].w; cp=cp+a[i].p; cx[i]=1; //装入背包 Force(i+1); cw=cw-a[i].w; cp=cp-a[i].p; cx[i]=0; //不装入背包 Force(i+1); return bestP; } int KnapSack1(int n,goodsa[],int C,int x[]) { Force(0); return bestP; } int main() { goods b[N]; printf("物品种数n: "); scanf("%d",&n); //输入物品种数 printf("背包容量C: "); scanf("%d",&C); //输入背包容量 for (int i=0;i { printf("物品%d的重量w[%d]及其价值v[%d]: ",i+1,i+1,i+1); scanf("%d%d",&a[i].w,&a[i].p); b[i]=a[i]; } int sum1=KnapSack1(n,a,C,X);//调用蛮力法求0/1背包问题 printf("蛮力法求解0/1背包问题:\nX=[ "); for(i=0;i cout< printf("] 装入总价值%d\n",sum1); bestP=0,cp=0,cw=0;//恢复初始化 } 2.1.3复杂度分析: 蛮力法求解0/1背包问题的时间复杂度为:2^n 2.2贪心算法(Greedy algorithm) 贪心算法通过一系列的选择来得到问题的解。贪心选择即它总是做出当前最好的选择[4]。贪心选择性质指所求问题的整体最优解可以通过一系列局部最优选择,这是贪心算法与动态规划算法的主要区别。 贪心算法每次只考虑一步,每一步数据的选取都必须满足局部最优条件。在枚举剩下数据与当前已经选取的数据组合获得的解中,提取其中能获得最优解的唯一的一个数据,加入结果数据中,直到剩下的数据不能再加入为止[6]。贪心算法不能保证得到的最后解是最佳的,也不能用来求最大或最小解问题,只能求满足某些约束条件的可行解围。 2.2.1算法设计 用贪心算法解决0-1背包问题一般有以下三种策略: ①价值最大者优先:在剩余物品中,选出可以装入背包的价值最大的物品,若背包有足够的容量,以此策略,然后是下一个价值最大的物品。但这种策略背包的承重量不能够得到有效利用,即得不到最优解。例如:n=3,w=[50,20,20],v=[10,7,7]c=55,得到的解是x=[1,0,0],这种方案的总价值为10,而最优解为[0,1,1],总价值为14。 ②重量最小者优先:在剩余物品中,选择可以装入背包的重量最小的物品。但这种策略,不能保证重量小的是最有价值的,也不能得到最优解。例如:n=2,w=[10,20],v=[5,100],c=25,得到的解为x=[1,0],而最优解是[0,1]。 ③单位价值最大者优先:根据价值与重量的比值i v /i w ,即单位价值,在剩下的物品中依次选取比值最大的物品装入背包。这种策略也不能得到最优解。例如:n=3,w=[20,15,15],v=[40,25,25],i v /i w =[2,5/3,5/3],c=30,得到的解x=[1,0,0],而最优解是[0,1,1]。但它是直觉上的一个近似解。本文讨论该策略。 策略3的具体步骤为: 第一步:计算每个物品的价值比i r =i v /i w ,i=1,2,…,n 。 第二步:对物品的价值比非递增排序。 第三步:重复下面操作,直到有序列表中留下物品。如果列表中的当前物品能够装入背包,就将它放入背包中,否则,处理下一个物品。 2.2.2 编程实现 #include"stdafx.h" #include using namespacestd; #define max 100 //自定义物品最大数void package(int v[],int w[],int n,int c) //定义包函数 { doublea[max]; inti,totalv=0,totalw=0,index[max]; for(i=0;i { a[i]=(double)v[i]/w[i]; //单位价值计算 index[i]=i; } for(i=1;i { for(int j=0;j {