程序设计方法-回溯、分支限界
来源:互联网 发布:淘宝怎么搜相册同款 编辑:程序博客网 时间:2024/06/04 18:53
背包问题为例:
头文件
#ifndef KNAP_H#define KNAP_H#include <iostream>using namespace std;//0-1 knapsack backtrace#define MaxSize 100 //最多物品数extern int limitw; //限制的总重量extern int maxwv; //存放最优解的总价值extern int maxw;extern int num_element; //实际物品数extern int option[MaxSize]; // 存放最终解extern int op[MaxSize]; //存放临时解struct node { int weight; int value;}; //存放物品数组extern node a[MaxSize]; void Knap(int i, int tw, int tv);// 0-1 knapsack branch boundextern int c; //限制的总重量extern int num_knap;struct good_node;extern good_node good[MaxSize];extern int best_node[MaxSize]; // node pointextern int bestp; //max profitstruct good_node { //kanp node int weight; int value; good_node() {} good_node(const good_node& a) { weight = a.weight; value = a.value; } good_node & operator =(const good_node &a) { weight = a.weight; value = a.value; } int operator >=(good_node &a) const { return (weight >= a.weight); }};struct tree_node { int index; bool is_used; tree_node* parent; tree_node():parent(NULL), index(0), is_used(0) {} tree_node(const tree_node & t) { parent = t.parent; index = t.index; is_used = t.is_used; } tree_node & operator =(const tree_node & t) { parent = t.parent; index = t.index; is_used = t.is_used; }};struct HeapNode { //heap node tree_node *node_ptr; int cw; int cp; int uprofit; HeapNode():node_ptr(NULL), cw(0), cp(0), uprofit(0) {} HeapNode(const HeapNode& h) { node_ptr = h.node_ptr; cw = h.cw; cp = h.cp; uprofit = h.uprofit; } HeapNode & operator =(const HeapNode& h) { node_ptr = h.node_ptr; cw = h.cw; cp = h.cp; uprofit = h.uprofit; } int operator >=(HeapNode &a) const { return (uprofit >= a.uprofit); } ~HeapNode();};class Heap { int capacity; int size; HeapNode *elem;public: Heap() {} Heap(int c, int s); void InsertH(HeapNode& x); HeapNode DeleteMaxH(); int get_size(); ~Heap();};int Bound(int i, int, int);void AddLiveNode(Heap &, tree_node* node_ptr, int cp, int cw, int up);void MaxKnapsack();//dm#endif
回溯
#include "knap.h"// 0-1 kanp backtracenode a[MaxSize];int limitw; //限制的总重量int maxwv; //存放最优解的总价值int maxw;int num_element; //实际物品数int option[MaxSize]; // 存放最终解int op[MaxSize]; void Knap(int i, int tw, int tv) { //考虑第i个物品 if(tw <= limitw) { if(i >= num_element) { //找到一个叶子结点 if (tv > maxwv) { //找到一个满足条件地更优解,保存它 cout << maxwv << endl; maxwv = tv; maxw= tw; for(int j = 0; j < num_element; j++) option[j] = op[j]; } } else { op[i] = 1; //选取第I个物品 Knap(i + 1, tw + a[i].weight, tv + a[i].value); op[i] = 0; //不选取第I个物品,回溯 Knap(i + 1, tw, tv); } } }分支限界:
#include "knap.h"int c;int num_knap;good_node good[MaxSize];int best_node[MaxSize] = {0};int bestp;HeapNode::~HeapNode() { //if(node_ptr != NULL) delete node_ptr;}Heap::Heap(int c, int s) { capacity = c; size = s; elem = new HeapNode[c];}void Heap::InsertH(HeapNode& x) { int sindex = 0;for(int i = 0; i < size; ++i) { if(elem[i] >= x) {sindex = i;break;}}for(int i = size; i > sindex; --i) {elem[i] = elem[i - 1];}elem[sindex] = x;++size;}HeapNode Heap::DeleteMaxH() { return elem[--size];}int Heap::get_size() { return size;}Heap::~Heap() { delete [] elem;}int Bound(int i, int cw, int cp) {//计算节点所相应价值的上界int cleft = c - cw; //剩余容量int b = cp; //价值上界//以物品单位重量价值递减序装填剩余容量while(i < num_knap && good[i].weight <= cleft) {cleft -= good[i].weight;b += good[i].value;i++;}if(i < num_knap) b += good[i].value * cleft / good[i].weight;if(i == num_knap) b+= good[i - 1].value * cleft / good[i - 1].weight;return b;}void AddLiveNode(Heap &h, tree_node* node_ptr, int cp, int cw, int up) {//将一个新的活结点插入到子集树和最大堆H中HeapNode N;N.node_ptr = node_ptr;N.cp = cp;N.cw = cw;N.uprofit = up;h.InsertH(N);}void MaxKnapsack() {//优先队列式分支限界法,返回最大价值,bestx返回最优解//定义对大堆得容量为1000//初始化int cw = 0;int cp = 0;int ubound ;Heap H(1000, 0);HeapNode N;tree_node* parent = NULL;//搜索子集空间树int i = 0; //node pointubound = Bound(i, cp, cw); //价值上界while(H.get_size() >= 0) { if(i == num_knap) { //update bestp, best_node int tmp_bestp = 0; int tmp_best_node[MaxSize] = {0}; while(parent != NULL) { int index = parent->index; bool is_used = parent->is_used; if(is_used) { tmp_best_node[index] = 1; tmp_bestp += good[index].value; } parent = parent->parent; } if(tmp_bestp > bestp) { bestp = tmp_bestp; for(int j = 0; j < num_knap; ++j) best_node[j] = tmp_best_node[j]; } } else { //检查当前扩展结点的左儿子节点 int tw = cw + good[i].weight; if(tw <= c) { //左儿子节点为可行结点 ubound = Bound(i, cp, cw); if(ubound >= bestp) { tree_node *tmp = new tree_node(); tmp->parent = parent; tmp->index = i; tmp->is_used = true; AddLiveNode(H, tmp, cp + good[i].value, cw + good[i].weight, ubound); } } //检查当前扩展结点的右儿子节点 ubound = Bound(i + 1, cp, cw); if(ubound >= bestp){ tree_node *tmp = new tree_node(); tmp->parent = parent; tmp->index = i; tmp->is_used = false; AddLiveNode(H, tmp, cp, cw, ubound); } } //取下一扩展结点 if(H.get_size() == 0) break; N = H.DeleteMaxH(); parent = N.node_ptr; i = parent->index + 1; cw = N.cw; cp = N.cp; }}测试:
#include <cstdlib>#include <iostream>#include "knap.h"using namespace std;int main(int argc, char *argv[]){ //0-1 knapsack backtrace num_element = 3; //3物品 a[0].weight = 16;a[0].value = 45; a[1].weight = 15;a[1].value = 25; a[2].weight = 15;a[2].value = 25; //a[3].weight=1;a[3].value=1; cout << a[0].weight << ',' << a[0].value << endl; maxwv = 0; maxw = 0; limitw = 30; //限制重量不超过30 Knap(0, 0, 0); cout << "最佳装填方案是:" << endl; for(int j = 0; j < num_element; j++) if(option[j] == 1) cout << "第"<< j + 1 << "种物品" << endl; cout << "总重量=" << maxw << ",总价值=" << maxwv << endl; //0-1 knapsack branch bound c = 30; num_knap =3; good[0].weight = 16;good[0].value = 45; good[1].weight = 15;good[1].value = 25; good[2].weight = 15;good[2].value = 25; bestp = 0; MaxKnapsack(); //cout << Bound(1, 0, 0) << endl; for(int i = 0; i < num_knap; ++i) cout << best_node[i] << ','; cout << endl; cout << bestp << endl; system("PAUSE"); return EXIT_SUCCESS;}
- 程序设计方法-回溯、分支限界
- 分支限界法vs回溯
- 回溯法与分支限界
- 分支限界法与回溯法
- 分支限界与回溯法对比
- 回溯法和分支限界法
- 分支限界与回溯法对比
- 回溯与分支限界算法-学习笔记
- 分支限界和回溯法的对比
- 分支限界与回溯法对比
- 回溯法与分支限界法
- 回溯法与分支限界算法
- 回溯法与分支限界法
- 回溯算法与分支限界法
- 一个分支限界和回溯法的例子
- 分支限界法和回溯法的区别
- 基础算法之回溯法、分支限界法
- 算法复习笔记(回溯法,分支限界法)
- Android_UI_实现TabHost的两种方法
- Android_makefile编译系统_Android.mk_文件语法规范
- 项目管理中的棘轮效应
- C++输入流
- 28 个必备的 Linux 命令行工具
- 程序设计方法-回溯、分支限界
- Android系统移植技术详解
- cpu 调优
- 安装后如何配置SharePoint 2010
- 转 ffmpeg图象倒置
- 禅修程序员十诫
- activity stack
- 谈谈Runtime类中的freeMemory,totalMemory,maxMemory等几个方法 Java虚拟机threadJVM
- POJ2000浅析------Gold Coins