14天阅读挑战赛
努力是为了不平庸~
算法实例——0/1背包问题
题目描述
有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。
问题分析
- 目标函数:∑pi最大,使装入背包的所有物品p的价值加起来最大。
- 约束条件:装入的物品总重量不能超过背包容量:∑wi<=M( M=150)
- 贪心策略:
(1)选择价值最大的物品
(2)选择重量最小的物品
(3)选择单位重量价值最大的物品
做题思路(三种策略)
策略一:选择价值最大的物品
根据这个策略最终选择装入背包的物品依次是D、B、F、E,此时包的总重量是130,总价值是165。
代码实现:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
//定义待选物体的结构体类型
struct node
{
double w;//重量
double v;//价值
} we[100] ;
//定义背包问题
bool cmp1(node a ,node b)//价值
{
if(a.v==b.v)
return a.w<b.w;
return a.v>b.v;
}
//将已经确定要装入背包的物品装入
int fun1(int n,int c)
{
sort(we,we+n,cmp1);
int value=0;
for(int i=0; i<n; i++)
{
if(c>=we[i].w)
{
c-=we[i].w;
value+=we[i].v;
}
}
return value;
}
int main(void)
{
int n,c,sum;//n个物品,c的容量,sum的价值
cin>>n>>c;
for(int i=0; i<n; i++)
cin>>we[i].w;
for(int j=0; j<n; j++)
cin>>we[j].v;
sum=fun1(n,c);
cout<<sum<<endl;
}
测试结果:
7 150
35 30 60 50 40 10 25
10 40 30 50 35 40 30
165
--------------------------------
Process exited after 28.52 seconds with return value 0
请按任意键继续. . .
注意:在用sort进行排序时,要加入头文件"algorithm"。
策略二:选择重量最小的物品
根据这个策略最终选择装入背包的物品编号依次是 F、G、B、A、E,此时包中物品总重量是 140,总价值是 155。
代码实现:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
//定义待选物体的结构体类型
struct node
{
double w;//重量
double v;//价值
} we[100] ;
//定义背包问题
bool cmp2(node a ,node b)//重量
{
if(a.w==b.w)
return a.v>b.v;
return a.w<b.w;
}
//将已经确定要装入背包的物品装入
int fun2(int n,int c)
{
sort(we,we+n,cmp2);
int value=0;
for(int i=0; i<n; i++)
{
if(c>=we[i].w)
{
c-=we[i].w;
value+=we[i].v;
}
}
return value;
}
int main(void)
{
int n,c,sum;//n个物品,c的容量,sum的价值
cin>>n>>c;
for(int i=0; i<n; i++)
cin>>we[i].w;
for(int j=0; j<n; j++)
cin>>we[j].v;
sum=fun2(n,c);
cout<<sum<<endl;
}
测试结果:
7 150
35 30 60 50 40 10 25
10 40 30 50 35 40 30
155
--------------------------------
Process exited after 28.52 seconds with return value 0
请按任意键继续. . .
策略三:选择单位重量价值最大的物品
物品的价值密度 si 定义为 pi/wi,这 7 件物品的价值密度分别为 si=[0.286,1.333,0.5,1.0,0.875,4.0,1.2]。根据这个策略最终选择装入背包的物品编号依次是 F、B、G、D、A,此时包中物品的总重量是 150,总价值是 170。
** 代码实现:**
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
//定义待选物体的结构体类型
struct node
{
double w;//重量
double v;//价值
} we[100] ;
//定义背包问题
bool cmp3(node a,node b)// 单位价值
{
if((a.v/a.w)==(b.v/b.w))
return a.w<b.w;
return (a.v/a.w)>(b.v/b.w);
}
//将已经确定要装入背包的物品装入
int fun3(int n,int c)
{
sort(we,we+n,cmp3);
int value=0;
for(int i=0; i<n; i++)
{
if(c>=we[i].w)
{
c-=we[i].w;
value+=we[i].v;
}
}
return value;
}
int main(void)
{
int n,c,sum;//n个物品,c的容量,sum的价值
cin>>n>>c;
for(int i=0; i<n; i++)
cin>>we[i].w;
for(int j=0; j<n; j++)
cin>>we[j].v;
sum=fun3(n,c);
cout<<sum<<endl;
}
7 150
35 30 60 50 40 10 25
10 40 30 50 35 40 30
170
--------------------------------
Process exited after 166.5 seconds with return value 0
请按任意键继续. . .
总结
0/1背包问题的贪心算法的三个策略不一样,但实现的过程都是类似的,都是通过选择当前看上去最好的一个方案,在一定条件下,贪心算法是0/1背包问题的较好的算法,但不是所有0/1背包问题都可以通过贪心算法找到最优解,只能通过贪心算法求得局部最优解,而涉及到贪心无法解决的0/1背包问题,这时就要用动态规化等算法来解决。
继续加油,学习更多有趣的算法!如有问题请指出,新手创作,如有帮助请给个赞!