1. 问题描述
2. 问题分析
队列式分支限界法与优先队列式分支限界法搜索对比
3. 算法设计
#include<cstdlib>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
//问题表示
const int MAXN = 50;
int n = 4, W = 10;
int w[] = { 0, 4, 7, 5, 3 }; //重量,下标0不用
int v[] = { 0, 40, 42, 25,12 }; //价值,下标0不用
//求解结果表示
int maxv = 0; //存放最大价值,初始为最小值
int bestx[MAXN]; //存放最优解,全局变量
int total = 1; //解空间中结点数累计,全局变量
//队列中的结点类型
typedef struct NodeType {
int number; //结点编号
int index; //当前结点在搜索空间中的层次
int weight; //当前结点的总重量
int value; //当前结点的总价值
int x[MAXN]; //当前结点包含的解向量
double ub; //上界
bool operator<(const NodeType& s) const { //重载<关系函数
return ub < s.ub; //ub越大越优先出队
}
};
//计算分枝结点e的上界
void bound(NodeType& e) {
int index = e.index + 1; //考虑结点e的余下物品
int sumw = e.weight; //求已装入的总重量
double sumv = e.value; //求已装入的总价值
while ((sumw + w[index] <= W) && index <= n) {
sumw += w[index]; //剩余容量里,可完整装入背包的物品总重量
sumv += v[index]; //剩余容量里,可完整装入背包的物品总价值
index++;
}
if (index <= n) //余下物品只能部分装入
e.ub = sumv + (W - sumw) * v[index] / w[index];
else
e.ub = sumw;
}
//结点e进队qu
void EnQueue(NodeType e, priority_queue<NodeType>& qu) {
if (e.index == n) { //到达叶结点
if (e.value > maxv) { //找到更大价值的解
maxv = e.value;
for (int i = 1; i <= n; i++)
bestx[i] = e.x[i];
}
}
else
qu.push(e); //非叶结点进队
}
//求0/1背包的最优解
void bfs() {
int j;
NodeType e, e1, e2; //定义3个结点
priority_queue<NodeType> qu; //定义一个优先队列(大根堆)
e.index = 0; //根结点置初值,其层次记为0
e.weight = 0;
e.value = 0;
e.number = total++;
for (j = 1; j <= n;j++)
e.x[j] = 0;
bound(e); //求根结点的上界
qu.push(e); //根结点进队
while (!qu.empty()) { //队不空则循环
e = qu.top();
qu.pop(); //出队结点e
if (e.ub >= maxv) {
if (e.weight + w[e.index + 1] <= W) { //判断左孩子结点是否超重? --剪枝
e1.number = total++;
e1.index = e.index + 1; //建立左孩子结点
e1.value = e.value + v[e1.index];
for (j = 1; j <= n; j++) //复制解向量
e1.x[j] = e.x[j];
e1.x[e1.index] = 1;
bound(e1); //求左孩子结点的上界
EnQueue(e1, qu); //左孩子结点进队操作
}
e2.number = total++; //建立右孩子结点
e2.index = e.index + 1;
e2.weight = e.weight;
e2.value = e.value;
for (j = 1; j <= n; j++) //复制解向量
e2.x[j] = e.x[j];
e2.x[e2.index] = 0;
bound(e2); //求右孩子结点的上界
if (e2.ub >= maxv) //右孩子结点限界函数是否小于maxv--剪枝
EnQueue(e2, qu);
}
}
}
int main() {
int W_temp = W;
bfs();
cout << "\n优先队列式分支限界法求解0/1背包问题:\n最优解:X=[";
for (int i = 1; i <= n; i++) //输出最优解
cout << bestx[i] << ","; //输出所求X[n]数组
cout << "]\n最大价值:" << maxv << "\n";
return 0;
}