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

背包问题为例:

头文件

#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 bound
extern int c;  //限制的总重量
extern int num_knap;
struct good_node;
extern good_node good[MaxSize];
extern int best_node[MaxSize]; // node point
extern int bestp; //max profit

struct 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 backtrace
node 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 point
	ubound = 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;
}




你可能感兴趣的:(struct,tree,null,delete,扩展,branch)