一、关于一般背包问题
1. 问题描述:
- 设有n个物品和一个背包,物品i的重量为wi,价值为vi,背包的容量为C。若将物品i的xi部分(1≤i≤n,0≤xi≤1)装入背包,则具有价值为vixi。
- 目的是找到一个方案,使放入背包的物品总价值最高。
- 与0-1背包问题类似,不同的是在选择物品 i 装入背包时,可以选择物品 i 的一部分,而不一定要全部装入背包。
2. 问题分析:
- 思考:
- 贪心算法总是作出在当前看来最好的选择,或者说在某种意义上的局部最优选择。
- 因此,在考虑放入物品时,应当选择所有(剩余)物品中价值比(*单位重量的价值)最高的一个放入,然后考虑背包(剩余)容量,选择放入物品的多少部分。
- 最终找到一个n元向量(x1, …, xn)(0≤xi≤1),使得 ∑ i = 1 n w i x i ≤ c \sum_{i=1}^n w_ix_i \leq c ∑i=1nwixi≤c,且 m a x ∑ i = 1 n v i x i max\sum_{i=1}^n v_ix_i max∑i=1nvixi。
- 得出算法思路:
- 各物体按单位价值由高到低排序;
- 取价值最高者放入背包;
- 计算背包剩余空间;
- 在剩余物体中取价值最高者放入背包;
- 重复2, 3, 4步,直到背包剩余容量为0或物品全部装入背包为止。
- 该算法的主要时间在于:将各种物品依其单位重量的价值从大到小排序。
二、算法实现
1. 贪心算法
//一般背包问题 贪心算法
#include <iostream>
using namespace std;
void knapsack(int n, double M, double v[], double w[], double x[]); // 背包算法
int main()
{
cout << "一般背包问题的贪心算法\n\n";
const int n = 4; // 物品个数
double C = 50; // 背包所能容纳的重量
double x[n + 1]; // 物品选择向量
double w[] = { 0,10,20,30,40 }; // 下标从1开始,物品i的重量(已按单位价值减序排序)
double v[] = { 0,60,100,120,120 }; // 下标从1开始,物品i的价值(已按单位价值减序排序)
cout << "背包所能容纳的重量为:" << C << endl;
cout << "物品的重量和价值分别为:" << endl;
for (int i = 1; i <= n; i++)
cout << "[" << i << "]:(" << w[i] << "," << v[i] << ")" << endl;
knapsack(n, C, w, v, x);
cout << "\n物品选择向量为:(";
for (int i = 1; i <= n; i++)
{
cout << x[i];
if (i + 1 <= n)
cout << ",";
else
cout << ")\n";
}
return 0;
}
void knapsack(int n, double C, double w[], double v[], double x[])
{
// 对物品按单位价值排序
// sort(n, w, v);
// 所有元素设为0,背包初始状态(没有装入任何物品)
memset(x, 0, sizeof(double) * (n + 1));
int i; // 第 i 个物品
double c = C; // 背包剩余容量
// 物品i整件被装下,x[i]=1
for (i = 1;i <= n;i++)
{
if (w[i] > c)
break;
x[i] = 1;
c -= w[i];
}
// 物品i只有部分被装下,x[i] = c / w[i];
if (i <= n)
x[i] = c / w[i];
}
2. 运行结果展示
·
三、友情链接~
- 其它一些常见算法请参阅此链接~
最后,非常欢迎大家来讨论指正哦!