利用优先队列,以结点的价值上界作为优先值.这里要用到的头文件:
它的特点是会在内部按特征值自动排序
当优先队列的数据结构是struct时写法如下
struct PState
{
....
//成员函数、构造函数、数据成员部分
friend bool operator <(const PState& a, const PState& b)
{
return a.up < b.up; //up值从小到大--推算-->优先级从小到大
}
};
priority_queue q;
分为三部分:全局变量 & 上界函数 & 遍历函数 & 初始化及调用及打印函数
1.全局变量
#include"allh.h"
//采用优先队列的01背包问题
//Priority_queue是可排序的queue,top()返回最大值元素
//物品结构
vectorW2 = { 2,5,4,2 };
vectorV2 = { 6,3,5,4 };
int N2 = (int)V2.size();
int bestp2; //记录最优值
vectorbestx2; //记录最优解
int Volume2; //记录购物车总容量
int sumv2, sumw2; //全部物品总重量和总价值
//性价比结构,用于排序
struct Object
{
int id; //表示顺序
double quo; //记录性价比
};
2.上界函数Bound(),注意数据类型
//上界函数,需要id,rw,cp
double Bound(PState t)
{
double resValue=0;
int num = t.id; //排序后的即将判断的物品序号
double residue = t.rw; //当前状态的剩余容量
while (num < N2 && W2[num] <= residue)
{
resValue += V2[num];
residue -= W2[num];
num++;
}
if (num < N2)
resValue += double(V2[num]) / W2[num] * residue; //01背包问题在计算上界时,分割计算上界
return resValue + t.cp; //最大上界=状态当前价值+剩余空间能装的最大价值
}
3.遍历函数,改用q.top()获取栈顶元素
int Priority_BFS_01Backpack()
{
int t;//当前物品序号
double tup; //保存价值上界
priority_queueq1;
q1.push(PState(0, sumv2, Volume2, 0));//已有物品总值,剩余物品总值,剩余容量,物品序号
while (!q1.empty()) //开始循环
{
PState livenode, lchild, rchild; //每次循环创建当前结点,左子树,右子树
livenode = q1.top(); //上一次while循环入队的左右孩子成为了新的livenode
q1.pop();
t = livenode.id;
//活结点的约束条件(终止循环条件)
if (t >= N2 || livenode.rw == 0)//物品序号 t=[0,N-1] || 当前状态的剩余空间==0
{
//多个可行解中得最优值
if (livenode.cp >= bestp2)
{
bestx2 = livenode.x;
bestp2 = livenode.cp;
}
continue;
}
//对活结点的限界条件
if (livenode.up < bestp2)
continue;
//左子树
if (livenode.rw >= W2[t]) //约束条件:剩余容量装得下当前物品
{
//创建左孩子
lchild.cp = livenode.cp + V2[t];
lchild.rw = livenode.rw - W2[t];
lchild.id = t + 1;
lchild.up = Bound(lchild);
lchild.x = livenode.x; lchild.x[t] = true;
if (lchild.cp > bestp2) //当前解>最优解才更新
bestp2 = lchild.cp;
q1.push(lchild);
}
//右子树
rchild.cp = livenode.cp;
rchild.rw = livenode.rw;
rchild.id = t + 1;
tup = Bound(rchild);
if (tup >= bestp2)
{
rchild.up =Bound(rchild);
rchild.x = livenode.x;
rchild.x[t] = false;
/*rchild = PState(rchild.cp, rchild.up, rchild.rw, rchild.id);*/ //因为构造函数,这一行会变回默认值
q1.push(rchild);
}
}
return bestp2;
}
4.调用函数
void Prio_backpack()
{
//初始化
bestp2 = 0;
Volume2 = 10;
bestx2.resize(N2);
sumw2 = accumulate(W2.begin(), W2.end(), 0); //记录总重量
sumv2 = accumulate(V2.begin(), V2.end(), 0); //记录总价值
//对性价比排序
vector
1.因累赘的构造函数导致的不出现最佳策略.
初次调试:
调试发现在左右子树的该语句中,child.x[]继承了livenode.x[]后又被构造函数初始化为{0,0,0....} .这一句完全是多余的
删除后显示成功.
2.在Bound()上界函数的定义中, up已经是当前值+剩余所有值,在调用Bound()时, 不应该再加一次cp
3.bound()中, res的数据类型写错了.应该是double
先看一段代码
queueq;
q.push(5); q.push(2); q.push(3);
int* p= &q.front();
q.pop();
cout << *p;
输出是5.
元素5在pop()后仍存在于内存中,仅仅是出队了而已.
可以用指针指向livenode结点的父结点和左右子结点.得到最优解时一路返回.
3个State* 指针所花费的空间 < 一个bool [ n ]解向量 (n比较大时)