(一)回溯算法+分支限定解决01背包
//动态规划的背包问题可以看我的之前博客
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 10
struct Goods_Info
{
double v; //价值
double w; //重量
double vw; //价值重量比
}goods[MAXN];
int maxValue;
bool x[MAXN];
bool optimalSolu[MAXN];
int c; int n;;
bool Cmp(const Goods_Info a, const Goods_Info b)
{
return a.vw > b.vw;
}
//可装入一部分物品时,取得的最优价值
double Bound(int i, double v, int c) //c是背包剩余承重,v是背包现在的总价值
{
//代价函数:以物品的价值重量比递减将物品装入背包 (贪心法)捡着单位重量价值最大的物品装
//这里与完全背包的代价函数不同,完全背包是以完全装第K+1件物品至装满
while (i <= n && goods[i].w <= c)
{
v += goods[i].v;
c -= goods[i].w;
i++;
}
//将背包装满
if (i <= n)
{
v += (goods[i].vw * c);
}
return v;
}
void Backtrack(int k, int cv, int rc)
{
if (k > n) //回溯算法递归套路
{
if (cv > maxValue)
{
maxValue = cv; //当所有物品遍历完后,maxValue 是界函数值
int i;
for (i = 1; i <= n; i++)
{
optimalSolu[i] = x[i];
}
}
}
else
{
if (goods[k].w <= rc) //当前物品能否装入背包
{
x[k] = true;
Backtrack(k + 1, cv + goods[k].v, rc - goods[k].w);
}//回溯时候会回到这里,就是决定如果不装第k件会不会更好,如果存在更好的可能(单位重量最大价值*剩余重量,//也就是最理想的情况),
//我们就试下不装第k件,反正目前的最优解已经记录到了optimalSolu[]
if (Bound(k + 1, cv, rc)> maxValue) //与界函数比下,剩余物品的最优价值是否更优 值得往下继续算不?
{
x[k] = false;
Backtrack(k + 1, cv, rc);
}
}
}
int main(void)
{
//为简洁起见我这里把物品的价值和重量直接写出
goods[1].v = 9.0; goods[1].w = 7.0;
goods[2].v = 5.0; goods[2].w = 4.0;
goods[3].v = 3.0; goods[3].w = 3.0;
goods[4].v = 1.0; goods[4].w = 2.0;
cin >> n >> c;//n是物品总类别数目,c是背包最大限重
for (int i = 1; i <= n; i++)
{
goods[i].vw = goods[i].v / goods[i].w;//计算各种物品单位重量价值
}
//将物品按照价值重量比递减排序
sort(goods + 1, goods + n + 1, Cmp);
// cout << goods[1].vw << " " << goods[2].vw << " " << goods[3].vw << " " << goods[4].vw << endl;
Backtrack(1, 0, c);
printf("%d\n", maxValue); //最优值
return 0;
}
(二)回溯算法+分支限定解决完全背包问题
/**************程序实现:完全背包的回溯算法+分支限定的C++实现************/
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 10
struct Goods_Info
{
int v; //价值
int w; //重量
double vw; //价值重量比
}goods[MAXN];
int n, c;
int maxValue;
int x[MAXN] = {0};
int optimal[MAXN] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
double tempMaxValue;
//可装入一部分物品时,取得的最优价值
double Bound(int i, double v, int c)
{
v += goods[i].vw*c;
return v;
}
bool Cmp(const Goods_Info a, const Goods_Info b)
{
return a.vw > b.vw;
}
void Backtrack(int k, int cv, int rc)
{
if (k > n) //回溯算法递归套路
{
if (cv > maxValue)
{
maxValue = cv; //当所有物品遍历完后,maxValue 是界函数值
int i;
for (i = 1; i <= n; i++)
{
optimal[i] = x[i];
}
}
}
else
{
for (int j = rc/goods[k].w; j >=0; --j)
//对于第k件物品,理论上最多可装rc/goods[k].w 所以面对第k件物品不再是01两种选择,而是
//0、1、....j共j+1种选择
{
if (j*goods[k].w<=rc)
{
x[k] = j;
Backtrack(k + 1, cv + j*goods[k].v, rc - j*goods[k].w);
}
}
if (Bound(k + 1, cv, rc) > maxValue)
{
if (x[k] > 0)
x[k]--;
Backtrack(k + 1, cv + x[k]*goods[k].v, rc - x[k]*goods[k].w);
}
}
}
int main(void)
{
cout << "请输入物体总的类别数目n: "; cin >> n;
cout << "请输入背包限制的总重量c: "; cin >> c;
cout << "请输入物品分别的价值和其对应的重量: ";
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &goods[i].v, &goods[i].w);
goods[i].vw = (double)goods[i].v / goods[i].w;
}
//将物品按照价值重量比递减排序
sort(goods + 1, goods + n + 1, Cmp);
Backtrack(1, 0, c);
cout << "完全背包的条件下背包的最大价值可以达到:";
printf("%d\n", maxValue); //最优值
cout << "按单位质量最大价值的顺序,分别取得物品件数是: ";
for (int j = 1; j <= n; ++j)
cout << optimal[j] << " ";
cout << endl;
}