通过贪心算法来解决背包问题
给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量 ,价值wi (1≤i≤n),要求把物品装满背包,且使背包内的物品价值最大。 有两类背包问题(根据物品是否可以分割),如果物品不可以分割,称为0—1背包问题(动态规划);如果物品可以分割,则称为背包问题(贪心算法)。
假设xi是物品i装入背包的部分(0≤xi≤1),当xi=0时表示物品i没有被装入背包;当xi=1时表示物品i被全部装入背包。
有3种方法来选取物品:
(1)当作0—1背包问题,用动态规划算法,获得最优值220;
(2)当作0—1背包问题,用贪心算法,按性价比从高到底顺序选取物品,获得最优值160。由于物品不可分割,剩下的空间白白浪费。
(3)当作背包问题,用贪心算法,按性价比从高到底的顺序选取物品,获得最优值240。由于物品可以分割,剩下的空间装入物品3的一部分,而获得了更好的性能。
注意:
1.在动态规划算法中,每步的选择往往依赖于相关子问题的解,因而只有在解出相关子问题后,才能做出选择。
2.在贪心算法中,仅在当前做出最好的选择,即局部最优选择,然后再去解出这个选择后的相应子问题。
我在这里写的是通过贪心算法来解决背包问题。
其中,0≤xi≤1。
n | 1 | 2 | 3 |
---|---|---|---|
重量 | 10 | 20 | 30 |
价值 | 60 | 100 | 120 |
性价比 | 6 | 5 | 4 |
#include<bits/stdc++.h>
using namespace std;
struct bag{
int w; //物品的重量
int v; //物品的价值
double c; //性价比
}a[1001]; //存放物品的数组
bool cmp(bag a,bag b)//按性价比降序排序
{
return a.c>b.c;
}
double knapsack(int n,bag a[],double c)//物品数量 按物品的性价比降序排序后的数组 背包的容量
{
double cleft=c; //背包剩余容量
int i=0;
double b=0;
while(i<n&&a[i].w<cleft) //背包仍能装下物品i
{
cleft-=a[i].w;
b+=a[i].v;
i++;
}
if(i<n)b+=1.0*a[i].v*cleft/a[i].w;//物品i不能被完整装下,用物品i装满背包的剩余空间
return b; //返回最高价值
}
int main()
{
for(int i=0;i<=2;i++)//10 60 6 20 100 5 30 120 4
{
cin>>a[i].w>>a[i].v>>a[i].c;
}
double c=knapsack(3,a,50);
cout<<c;
}
如果要获得解向量,则需要在数据结构中加入物品编号与装入量。
#include<bits/stdc++.h>
using namespace std;
struct bag{
int w; //物品的重量
int v; //物品的价值
double x; //装入背包的量
int index; //物品编号
double c; //性价比
}a[1001]; //存放物品的数组
bool cmp(bag a,bag b) //按性价比降序排序
{
return a.c>b.c;
}
knapsack(int n,bag a[],double c)//物品数量 按物品的性价比降序排序后的数组 背包的容量
{
double cleft=c; //背包剩余容量
int i=0;
double b=0;
while(i<n&&a[i].w<cleft) //背包仍能装下物品i
{
cleft-=a[i].w;
b+=a[i].v;
a[a[i].index].x=1.0;
i++;
}
if(i<n)//物品i不能被完整装下,用物品i装满背包的剩余空间
{
a[a[i].index].x=1.0*cleft/a[i].w;
b+=a[a[i].index].x*a[i].v;
}
cout<<b<<endl; //输出最大值和解向量
for(int i=0;i<=2;i++)
cout<<a[i].x<<" ";
}
int main()
{
for(int i=0;i<=2;i++)//10 60 6 1 20 100 5 2 30 120 4 3
{
cin>>a[i].w>>a[i].v>>a[i].c>>a[i].index;
}
knapsack(3,a,50);
}