程序设计方法-回溯、分支限界

来源:互联网 发布:淘宝怎么搜相册同款 编辑:程序博客网 时间: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;}




原创粉丝点击