設計如下
這個pdf文檔有點長,截圖分段了,需要可以直接下載該文檔
代碼如下
//author:rgh
//採用優先隊列式分枝限界法求解0/1揹包問題
#include <stdio.h>
#include <queue>
using namespace std;
#define MAXN 20 //最多可能物品數
//問題表示
int n=3,W=30;
int w[]={0,16,15,15}; //重量,下標0不用
int v[]={0,45,25,25}; //價值,下標0不用
//求解結果表示
int maxv=-9999; //存放最大價值,初始爲最小值
int bestx[MAXN]; //存放最優解,全局變量
int total=1; //解空間中結點數累計,全局變量
struct NodeType //隊列中的結點類型
{ int no; //結點編號
int i; //當前結點在搜索空間中的層次
int w; //當前結點的總重量
int v; //當前結點的總價值
int x[MAXN]; //當前結點包含的解向量
double ub; //上界
};
void bound(NodeType &e) //計算分枝結點e的上界
{
int i=e.i+1;
int sumw=e.w;
double sumv=e.v;
while ((sumw+w[i]<=W) && i<=n)
{ sumw+=w[i]; //計算揹包已裝入載重
sumv+=v[i]; //計算揹包已裝入價值
i++;
}
if (i<=n)
e.ub=sumv+(W-sumw)*v[i]/w[i];
else
e.ub=sumv;
}
void EnQueue(NodeType e,queue<NodeType> &qu) //結點e進隊qu
{
if (e.i==n) //到達葉子結點
{
if (e.v>maxv) //找到更大價值的解
{
maxv=e.v;
for (int j=1;j<=n;j++)
bestx[j]=e.x[j];
}
}
else qu.push(e); //非葉子結點進隊
}
void bfs() //求0/1揹包的最優解
{
int j;
NodeType e,e1,e2; //定義3個結點
queue<NodeType> qu; //定義一個隊列
e.i=0; //根結點置初值,其層次計爲0
e.w=0; e.v=0;
e.no=total++;
for (j=1;j<=n;j++)
e.x[j]=0;
bound(e); //求根結點的上界
qu.push(e); //根結點進隊
while (!qu.empty()) //隊不空循環
{
e=qu.front(); qu.pop(); //出隊結點e
if (e.w+w[e.i+1]<=W) //剪枝:檢查左孩子結點
{
e1.no=total++;
e1.i=e.i+1; //建立左孩子結點
e1.w=e.w+w[e1.i];
e1.v=e.v+v[e1.i];
for (j=1;j<=n;j++) //複製解向量
e1.x[j]=e.x[j];
e1.x[e1.i]=1;
bound(e1); //求左孩子結點的上界
EnQueue(e1,qu); //左孩子結點進隊操作
}
e2.no=total++; //建立右孩子結點
e2.i=e.i+1;
e2.w=e.w; e2.v=e.v;
for (j=1;j<=n;j++) //複製解向量
e2.x[j]=e.x[j];
e2.x[e2.i]=0;
bound(e2); //求右孩子結點的上界
//輸出右孩子
printf("輸出右孩子 e2.no=%d,e2.i=%d,e2.ub=%f\n", e2.no,e2.i,e2.ub) ;
if (e2.ub>maxv) //若右孩子結點可行,則進隊,否則被剪枝
EnQueue(e2,qu);
}
}
int main()
{
bfs(); //調用隊列式分枝限界法求0/1揹包問題
printf("分枝限界法求解0/1揹包問題:\n X=["); //輸出最優解
for(int i=1;i<=n;i++)
printf("%2d",bestx[i]); //輸出所求X[n]數組
printf("],裝入總價值爲%d\n",maxv);
}