#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; }
标签:01,PT,level,int,double,rightNode,限界,leftNode,法解 From: https://www.cnblogs.com/Jocelynn/p/17367052.html