#include <iostream>
using namespace std;
#define MAX 100
struct Node {
int isVisit;//记录节点是否被扩展
double w;
double v;
int level; //记录节点所在的层次
double ub; //上界
Node* parent; //父节点
};
double maxValue = 0;
Node* PT[MAX];
Node* maxofPT(int count) { //count代表PT现在有的节点数量,PT数组最后一个节点的下标
double max = 0; //找最大值
int r = -1; //r记录找到的最大值对应的PT的下标
for (int i = 0; i <= count; i++) {
if (PT[i]->ub > max && PT[i]->isVisit == 0) {
max = PT[i]->ub;
r = i;
}
}
PT[r]->isVisit = 1;//即将被扩展
return PT[r];
}
Node* bestLeaf(int count, int n) {//叶子节点就是所求解的节点
double max = 0;
int r = -1;
for (int i = 0; i <= count; i++) {
if (PT[i]->ub>max&&PT[i]->level == n) {
max = PT[i]->ub;
r = i;
}
}
return PT[r];
}
int* knapsack(double* w, double* v, int n, int capacity) {
//int x[n]; 这样写会报错“表达式必须具有常量值”
int* x = (int*)malloc(sizeof(int) * n);//申请一个数组存储最优解
int count = 0;//PT中现在节点的下标是0
double lb = 0;//下界值初始化为0
double weight = 0;//背包中现在装的物品容量为0
//初始化PT[0]
Node* initN = (Node*)malloc(sizeof(Node) * 1);
initN->isVisit = 0;
initN->v = 0;
initN->w = 0;
initN->level = 0;
initN->ub= capacity*(v[0]/w[0]); //初始上界值
initN->parent = NULL;
PT[count] = initN;
//贪心法求下界
for (int i = 0; i < n; i++) {
if (weight + w[i] <= capacity) {
weight += w[i];
lb += v[i];
}
}
// 选择扩展节点、剪枝、更新ub的过程如下
Node* expandNode = (Node*)malloc(sizeof(Node) * 1);
Node* bestNode = (Node*)malloc(sizeof(Node) * 1);
while (1) {
//从PT表中选择一个具有最大上界的节点作为扩展节点
//cout << "进入循环1次" << endl;
Node* leftNode = (Node*)malloc(sizeof(Node) * 1); //左边节点
Node* rightNode = (Node*)malloc(sizeof(Node) * 1); //右边节点
expandNode = maxofPT(count);
if (expandNode->level != n) {//如果expandNode->level==n,说明已经是叶子节点,不用再算了
//计算左节点
leftNode->isVisit = 0;
leftNode->v = expandNode->v + v[expandNode->level];
leftNode->w = expandNode->w + w[expandNode->level];
leftNode->level = expandNode->level + 1;
if (leftNode->level != n) {
leftNode->ub = leftNode->v +(capacity- leftNode->w)* v[leftNode->level] / w[leftNode->level];
}
else {
leftNode->ub = leftNode->v;
}
leftNode->parent = expandNode;
//加入PT表
if (leftNode->w <= capacity) {
PT[++count] = leftNode;
}
//计算右节点
rightNode->isVisit = 0;
rightNode->v = expandNode->v;
rightNode->w = expandNode->w;
rightNode->level = expandNode->level + 1;
if (rightNode->level != n) {
rightNode->ub = rightNode->v + (capacity - rightNode->w) * v[rightNode->level] / w[rightNode->level];
}
else {
rightNode->ub = rightNode->v;
}
rightNode->parent = expandNode;
//加入PT表
if (rightNode->w <= capacity) {
PT[++count] = rightNode;
}
}
else {
break;
}
}//while
bestNode = bestLeaf(count, n);//找到解
maxValue = bestNode->v;
//回溯法找到物品选择情况
for (int i = n-1; i >= 0; i--) {
if (bestNode->v == bestNode->parent->v) {
x[i] = 0;
}
else {
x[i] = 1;
}
bestNode = bestNode->parent;//向上一层回溯
}
return x;
}
int main() {
double w[]={2,2,3,1,5,2};
double v[]={2,3,1,5,4,3};
int c = 10;
int n = 6;
int* ans = (int*)malloc(sizeof(int) * n);
ans = knapsack(w, v, n, c);
cout << "最大价值: " << maxValue << endl;
cout << "最优解" << endl;
for (int i = 0; i < n; i++) {
cout << ans[i] << endl;
}
system("pause");
return 0;
}