一、 算法思想描述
首先对物体按照价值重量比进行排序。
再从第一个物体开始,对每个物体分两种状态求解:放入与不放入。
在每次求解时都计算该状态可能达到的最优价值,并放入大顶堆中。
当两种状态都求解完后从堆中取出堆顶元素,从该元素所代表的状态中继续进行分支计算。直到深度达到n,问题得到解。
二、 完整的程序以及说明
-
#include<iostream>
-
#include<algorithm>
-
using namespace std;
-
-
// 最多可能物体数
-
#define N 10
-
-
// 物体结构体
-
typedef struct {
-
float w; // 重量
-
float p; // 价值
-
float v; // 价值重量比
-
int num; // 编号
-
} OBJECT;
-
-
// 状态结构体
-
typedef struct {
-
bool s1 [N ]; // 当前放入物体
-
int k; // 搜索深度
-
float b; // 价值上界
-
float w; // 物体重量
-
float p; // 物体价值
-
} KNAPNODE;
-
-
// 堆元素结构体
-
typedef struct {
-
KNAPNODE *p; // 结点数据
-
float b; // 所指结点的上界
-
} HEAP;
-
-
/* 比较两个物体的价值比 */
-
bool cmp (OBJECT a, OBJECT b ) {
-
return a. v>b. v;
-
}
-
-
/* 交换两个堆元素 */
-
void swap (HEAP &a, HEAP &b ) {
-
HEAP tmp = a;
-
a = b;
-
b = tmp;
-
}
-
-
/* 堆中元素上移 */
-
void sift_up (HEAP H [ ], int i ) {
-
bool done = false;
-
if (i!= 1 ) {
-
while (!done && i!= 1 ) {
-
if (H [i ]. b>H [i/ 2 ]. b ) {
-
swap (H [i ], H [i/ 2 ] );
-
} else {
-
done = true;
-
}
-
i = i/ 2;
-
}
-
}
-
}
-
-
/* 堆中元素下移 */
-
void sift_down (HEAP H [ ], int n, int i ) {
-
bool done = false;
-
if ( ( 2*i )<=n ) {
-
while (!done && ((i = 2*i) <= n ) ) {
-
if (i +1<=n && H [i +1 ]. b > H [i ]. b ) {
-
i++;
-
}
-
if (H [i/ 2 ]. b<H [i ]. b ) {
-
swap (H [i/ 2 ], H [i ] );
-
} else {
-
done = true;
-
}
-
}
-
}
-
}
-
-
/* 往堆中插入结点 */
-
void insert (HEAP H [ ], HEAP x, int &n ) {
-
n++;
-
H [n ] = x;
-
sift_up (H,n );
-
}
-
-
/* 删除堆中结点 */
-
void del (HEAP H [ ], int &n, int i ) {
-
HEAP x, y;
-
x = H [i ]; y = H [n ];
-
n --;
-
if (i<=n ) {
-
H [i ] = y;
-
if (y. b>=x. b ) {
-
sift_up (H,i );
-
} else {
-
sift_down (H, n, i );
-
}
-
}
-
}
-
-
/* 获得堆顶元素并删除 */
-
HEAP delete_max (HEAP H [ ], int &n ) {
-
HEAP x = H [ 1 ];
-
del (H, n, 1 );
-
return x;
-
}
-
-
/* 计算分支节点的上界 */
-
void bound ( KNAPNODE* node, float M, OBJECT ob [ ], int n ) {
-
int i = node->k;
-
float w = node->w;
-
float p = node->p;
-
if (node->w>M ) { // 物体重量超过背包载重量
-
node->b = 0; // 上界置为0
-
} else {
-
while ( (w+ob [i ]. w<=M )&& (i<n ) ) { // 否则
-
w += ob [i ]. w; // 计算背包已装入载重
-
p += ob [i++ ]. p; // 计算背包已装入价值
-
}
-
if (i<n ) {
-
node->b = p + (M - w )*ob [i ]. p/ob [i ]. w;
-
} else {
-
node -> b = p;
-
}
-
}
-
}
-
-
/*
-
* 用分支限界法实现0/1背包问题
-
* 输入:包含n个物体的重量和价值的数组ob[],背包载重量M
-
* 输出:最优装入背包的物体obx[],装入背包的物体最优价值v
-
*/
-
float knapsack_bound (OBJECT ob [ ], float M, int n, int obx [ ] ) {
-
int i, k = 0; // 堆中元素个数的计数器初始化为0
-
float v;
-
KNAPNODE *xnode, *ynode, *znode;
-
HEAP x, y, z, *heap;
-
heap = new HEAP [n*n ]; // 分配堆的存储空间
-
for ( i= 0; i<n; i++ ) {
-
ob [i ]. v = ob [i ]. p/ob [i ]. w; // 计算物体的价值重量比
-
ob [i ]. num = i; // 记录物体的初始序号
-
}
-
sort (ob,ob+n,cmp ); // 对物体按照价值重量比排序
-
xnode = new KNAPNODE; // 建立父亲结点
-
for ( i= 0; i<n; i++ ) { // 初始化结点
-
xnode->s1 [i ] = false;
-
}
-
xnode->k = xnode->w = xnode->p = 0;
-
while (xnode->k<n ) {
-
ynode = new KNAPNODE; // 建立结点y
-
*ynode = *xnode; // 结点x的数据复制到结点y
-
ynode->s1 [ynode->k ] = true; // 装入第k个物体
-
ynode->w += ob [ynode->k ]. w; // 背包中物体重量累计
-
ynode->p += ob [ynode->k ]. p; // 背包中物体价值累计
-
ynode->k ++; // 搜索深度++
-
bound (ynode, M, ob, n ); // 计算结点y的上界
-
y. b = ynode->b;
-
y. p = ynode;
-
insert (heap, y, k ); // 结点y按上界的值插入堆中
-
znode = new KNAPNODE; // 建立结点z
-
*znode = *xnode; // 结点x的数据复制到结点z
-
znode->k++; // 搜索深度++
-
bound (znode, M, ob, n ); // 计算节点z的上界
-
z. b = znode->b;
-
z. p = znode;
-
insert (heap, z, k ); // 结点z按上界的值插入堆中
-
delete xnode;
-
x = delete_max (heap, k ); // 获得堆顶元素作为新的父亲结点
-
xnode = x. p;
-
}
-
v = xnode->p;
-
for ( i= 0; i<n; i++ ) { // 取装入背包中物体在排序前的序号
-
if (xnode->s1 [i ] ) {
-
obx [i ] = ob [i ]. num;
-
} else {
-
obx [i ] = -1;
-
}
-
}
-
delete xnode;
-
/* for(i=1; i<=k; i++) {
-
delete heap[i].p;
-
}*/
-
delete heap;
-
return v; // 返回背包中物体的价值
-
}
-
-
int main ( ) {
-
OBJECT ob [N ];
-
double m;
-
int n, i;
-
int obx [N ];
-
-
cout<< "请输入背包载重:";
-
cin>>m;
-
-
cout<< "请输入物品个数:";
-
cin>>n;
-
-
cout<< "请输入物品重量:";
-
for (i= 0; i<n; i++ ) {
-
cin>>ob [i ]. w;
-
}
-
-
cout<< "请输入物品价值:";
-
for (i= 0; i<n; i++ ) {
-
cin>>ob [i ]. p;
-
}
-
-
double v = knapsack_bound (ob, m, n, obx );
-
-
cout<< "装入背包的物体:"<<endl;
-
for ( i= 0; obx [i ]>= 0&&i<n; i++ ) {
-
cout<<obx [i ]<< " ";
-
}
-
cout<<endl;
-
cout<< "最优价值:"<<v<<endl;
-
-
return 0;
-
}
-