0036算法笔记——【分支限界法】0-1背包问题

         问题描述

     给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
     形式化描述:给定c >0, wi >0, vi >0 , 1≤i≤n.要求找一n元向量(x1,x2,…,xn,), xi∈{0,1}, ∋ ∑ wi xi≤c,且∑ vi xi达最大.即一个特殊的整数规划问题。

     算法设计

      首先,要对输入数据进行预处理,将各物品依其单位重量价值从大到小进行排列。在优先队列分支限界法中,节点的优先级由已装袋的物品价值加上剩下的最大单位重量价值的物品装满剩余容量的价值和。

     算法首先检查当前扩展结点的左儿子结点的可行性。如果该左儿子结点是可行结点,则将它加入到子集树和活结点优先队列中。当前扩展结点的右儿子结点一定是可行结点,仅当右儿子结点满足上界约束时才将它加入子集树和活结点优先队列。当扩展到叶节点时为问题的最优值。

     例如:0-1背包问题,当n=3时,w={16,15,15}, p={45,25,25}, c=30。优先队列式分支限界法:处理法则:价值大者优先。{}—>{A}—>{B,C}—>{C,D,E}—>{C,E}—>{C,J,K}—>{C}—>{F,G}—>{G,L,M}—>{G,M}—>{G}—>{N,O}—>{O}—>{}


       算法代码实现如下:

     1、MaxHeap.h

  1. template<class T>  
  2. class MaxHeap  
  3. {  
  4.     public:  
  5.         MaxHeap(int MaxHeapSize = 10);  
  6.         ~MaxHeap() {delete [] heap;}  
  7.         int Size() const {return CurrentSize;}  
  8.   
  9.         T Max()   
  10.         {          //查   
  11.            if (CurrentSize == 0)  
  12.            {  
  13.                 throw OutOfBounds();  
  14.            }  
  15.            return heap[1];  
  16.         }  
  17.   
  18.         MaxHeap<T>& Insert(const T& x); //增   
  19.         MaxHeap<T>& DeleteMax(T& x);   //删   
  20.   
  21.         void Initialize(T a[], int size, int ArraySize);  
  22.   
  23.     private:  
  24.         int CurrentSize, MaxSize;  
  25.         T *heap;  // element array   
  26. };  
  27.   
  28. template<class T>  
  29. MaxHeap<T>::MaxHeap(int MaxHeapSize)  
  30. {// Max heap constructor.   
  31.     MaxSize = MaxHeapSize;  
  32.     heap = new T[MaxSize+1];  
  33.     CurrentSize = 0;  
  34. }  
  35.   
  36. template<class T>  
  37. MaxHeap<T>& MaxHeap<T>::Insert(const T& x)  
  38. {// Insert x into the max heap.   
  39.     if (CurrentSize == MaxSize)  
  40.     {  
  41.         cout<<"no space!"<<endl;   
  42.         return *this;   
  43.     }  
  44.   
  45.     // 寻找新元素x的位置   
  46.     // i——初始为新叶节点的位置,逐层向上,寻找最终位置   
  47.     int i = ++CurrentSize;  
  48.     while (i != 1 && x > heap[i/2])  
  49.     {  
  50.         // i不是根节点,且其值大于父节点的值,需要继续调整   
  51.         heap[i] = heap[i/2]; // 父节点下降   
  52.         i /= 2;              // 继续向上,搜寻正确位置   
  53.     }  
  54.   
  55.    heap[i] = x;  
  56.    return *this;  
  57. }  
  58.   
  59. template<class T>  
  60. MaxHeap<T>& MaxHeap<T>::DeleteMax(T& x)  
  61. {// Set x to max element and delete max element from heap.   
  62.     // check if heap is empty   
  63.     if (CurrentSize == 0)  
  64.     {  
  65.         cout<<"Empty heap!"<<endl;   
  66.         return *this;   
  67.     }  
  68.   
  69.     x = heap[1]; // 删除最大元素   
  70.     // 重整堆   
  71.     T y = heap[CurrentSize--]; // 取最后一个节点,从根开始重整   
  72.   
  73.     // find place for y starting at root   
  74.     int i = 1,  // current node of heap   
  75.        ci = 2; // child of i   
  76.   
  77.     while (ci <= CurrentSize)   
  78.     {  
  79.         // 使ci指向i的两个孩子中较大者   
  80.         if (ci < CurrentSize && heap[ci] < heap[ci+1])  
  81.         {  
  82.             ci++;  
  83.         }  
  84.         // y的值大于等于孩子节点吗?   
  85.         if (y >= heap[ci])  
  86.         {  
  87.             break;   // 是,i就是y的正确位置,退出   
  88.         }  
  89.   
  90.         // 否,需要继续向下,重整堆   
  91.         heap[i] = heap[ci]; // 大于父节点的孩子节点上升   
  92.         i = ci;             // 向下一层,继续搜索正确位置   
  93.         ci *= 2;  
  94.     }  
  95.   
  96.     heap[i] = y;  
  97.     return *this;  
  98. }  
  99.   
  100. template<class T>  
  101. void MaxHeap<T>::Initialize(T a[], int size,int ArraySize)  
  102. {// Initialize max heap to array a.   
  103.     delete [] heap;  
  104.     heap = a;  
  105.     CurrentSize = size;  
  106.     MaxSize = ArraySize;  
  107.   
  108.     // 从最后一个内部节点开始,一直到根,对每个子树进行堆重整   
  109.    for (int i = CurrentSize/2; i >= 1; i--)  
  110.    {  
  111.         T y = heap[i]; // 子树根节点元素   
  112.         // find place to put y   
  113.         int c = 2*i; // parent of c is target   
  114.                    // location for y   
  115.         while (c <= CurrentSize)   
  116.         {  
  117.             // heap[c] should be larger sibling   
  118.             if (c < CurrentSize && heap[c] < heap[c+1])  
  119.             {  
  120.                 c++;  
  121.             }  
  122.             // can we put y in heap[c/2]?   
  123.             if (y >= heap[c])  
  124.             {  
  125.                 break;  // yes   
  126.             }  
  127.   
  128.             // no   
  129.             heap[c/2] = heap[c]; // move child up   
  130.             c *= 2; // move down a level   
  131.         }  
  132.         heap[c/2] = y;  
  133.     }  
  134. }  
template<class T>
class MaxHeap
{
	public:
		MaxHeap(int MaxHeapSize = 10);
		~MaxHeap() {delete [] heap;}
        int Size() const {return CurrentSize;}

        T Max() 
		{          //查
           if (CurrentSize == 0)
		   {
                throw OutOfBounds();
		   }
           return heap[1];
        }

		MaxHeap<T>& Insert(const T& x); //增
		MaxHeap<T>& DeleteMax(T& x);   //删

		void Initialize(T a[], int size, int ArraySize);

	private:
		int CurrentSize, MaxSize;
		T *heap;  // element array
};

template<class T>
MaxHeap<T>::MaxHeap(int MaxHeapSize)
{// Max heap constructor.
	MaxSize = MaxHeapSize;
	heap = new T[MaxSize+1];
	CurrentSize = 0;
}

template<class T>
MaxHeap<T>& MaxHeap<T>::Insert(const T& x)
{// Insert x into the max heap.
	if (CurrentSize == MaxSize)
	{
		cout<<"no space!"<<endl; 
		return *this; 
	}

    // 寻找新元素x的位置
    // i——初始为新叶节点的位置,逐层向上,寻找最终位置
	int i = ++CurrentSize;
	while (i != 1 && x > heap[i/2])
	{
		// i不是根节点,且其值大于父节点的值,需要继续调整
		heap[i] = heap[i/2]; // 父节点下降
		i /= 2;              // 继续向上,搜寻正确位置
    }

   heap[i] = x;
   return *this;
}

template<class T>
MaxHeap<T>& MaxHeap<T>::DeleteMax(T& x)
{// Set x to max element and delete max element from heap.
	// check if heap is empty
	if (CurrentSize == 0)
	{
		cout<<"Empty heap!"<<endl; 
		return *this; 
	}

	x = heap[1]; // 删除最大元素
	// 重整堆
	T y = heap[CurrentSize--]; // 取最后一个节点,从根开始重整

	// find place for y starting at root
	int i = 1,  // current node of heap
	   ci = 2; // child of i

	while (ci <= CurrentSize) 
    {
		// 使ci指向i的两个孩子中较大者
		if (ci < CurrentSize && heap[ci] < heap[ci+1])
		{
			ci++;
		}
		// y的值大于等于孩子节点吗?
		if (y >= heap[ci])
		{
			break;   // 是,i就是y的正确位置,退出
		}

		// 否,需要继续向下,重整堆
		heap[i] = heap[ci]; // 大于父节点的孩子节点上升
		i = ci;             // 向下一层,继续搜索正确位置
		ci *= 2;
    }

	heap[i] = y;
	return *this;
}

template<class T>
void MaxHeap<T>::Initialize(T a[], int size,int ArraySize)
{// Initialize max heap to array a.
	delete [] heap;
	heap = a;
	CurrentSize = size;
	MaxSize = ArraySize;

	// 从最后一个内部节点开始,一直到根,对每个子树进行堆重整
   for (int i = CurrentSize/2; i >= 1; i--)
   {
		T y = heap[i]; // 子树根节点元素
		// find place to put y
		int c = 2*i; // parent of c is target
                   // location for y
		while (c <= CurrentSize) 
		{
			// heap[c] should be larger sibling
			if (c < CurrentSize && heap[c] < heap[c+1])
			{
				c++;
			}
			// can we put y in heap[c/2]?
			if (y >= heap[c])
			{
				break;  // yes
			}

			// no
			heap[c/2] = heap[c]; // move child up
			c *= 2; // move down a level
        }
		heap[c/2] = y;
	}
}
     2、6d5.cpp

  1. //0-1背包问题 分支限界法求解    
  2. #include "stdafx.h"   
  3. #include "MaxHeap.h"   
  4. #include <iostream>   
  5. using namespace std;  
  6.   
  7. class Object  
  8. {  
  9.     template<class Typew,class Typep>  
  10.     friend Typep Knapsack(Typep p[],Typew w[],Typew c,int n, int bestx[]);  
  11.     public:  
  12.         int operator <= (Object a) const  
  13.         {  
  14.             return d>=a.d;  
  15.         }  
  16.     private:  
  17.         int ID;  
  18.         float d;//单位重量价值   
  19. };  
  20.   
  21. template<class Typew,class Typep> class Knap;  
  22.   
  23. class bbnode  
  24. {  
  25.     friend Knap<int,int>;  
  26.     template<class Typew,class Typep>  
  27.     friend Typep Knapsack(Typep p[],Typew w[],Typew c,int n, int bestx[]);  
  28.     private:  
  29.         bbnode * parent;    //指向父节点的指针   
  30.         bool LChild;        //左儿子节点标识   
  31. };  
  32.   
  33. template<class Typew,class Typep>  
  34. class HeapNode  
  35. {  
  36.     friend Knap<Typew,Typep>;  
  37.     public:  
  38.         operator Typep() const  
  39.         {  
  40.             return uprofit;  
  41.         }  
  42.     private:  
  43.         Typep uprofit,      //节点的价值上界   
  44.               profit;       //节点所相应的价值   
  45.         Typew weight;       //节点所相应的重量   
  46.         int level;          //活节点在子集树中所处的层序号   
  47.         bbnode *ptr;        //指向活节点在子集中相应节点的指针   
  48. };  
  49.   
  50. template<class Typew,class Typep>    
  51. class Knap    
  52. {    
  53.     template<class Typew,class Typep>  
  54.     friend Typep Knapsack(Typep p[],Typew w[],Typew c,int n, int bestx[]);  
  55.     public:  
  56.         Typep MaxKnapsack();  
  57.     private:    
  58.         MaxHeap<HeapNode<Typep,Typew>> *H;  
  59.         Typep Bound(int i);  
  60.         void AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int lev);  
  61.   
  62.         bbnode *E;  //指向扩展节点的指针   
  63.         Typew c;    //背包容量     
  64.         int n;      //物品数     
  65.     
  66.         Typew *w;   //物品重量数组     
  67.         Typep *p;   //物品价值数组     
  68.         Typew cw;   //当前重量     
  69.     
  70.         Typep cp;   //当前价值     
  71.         int *bestx; //最优解     
  72. };    
  73.   
  74. template <class Type>    
  75. inline void Swap(Type &a,Type &b);    
  76.     
  77. template<class Type>    
  78. void BubbleSort(Type a[],int n);   
  79.   
  80. int main()  
  81. {  
  82.     int n = 3;//物品数     
  83.     int c = 30;//背包容量     
  84.     int p[] = {0,45,25,25};//物品价值 下标从1开始     
  85.     int w[] = {0,16,15,15};//物品重量 下标从1开始     
  86.     int bestx[4];//最优解   
  87.     
  88.     cout<<"背包容量为:"<<c<<endl;    
  89.     cout<<"物品重量和价值分别为:"<<endl;    
  90.     
  91.     for(int i=1; i<=n; i++)    
  92.     {    
  93.         cout<<"("<<w[i]<<","<<p[i]<<") ";    
  94.     }    
  95.     cout<<endl;    
  96.     
  97.     cout<<"背包能装下的最大价值为:"<<Knapsack(p,w,c,n,bestx)<<endl;    
  98.     cout<<"此背包问题最优解为:"<<endl;  
  99.     for(int i=1; i<=n; i++)  
  100.     {  
  101.         cout<<bestx[i]<<" ";  
  102.     }  
  103.     cout<<endl;  
  104.     return 0;    
  105. }  
  106.   
  107. template<class Typew,class Typep>  
  108. Typep Knap<Typew,Typep>::Bound(int i)//计算节点所相应价值的上界   
  109. {  
  110.     Typew cleft = c-cw; //剩余容量高   
  111.     Typep b = cp;       //价值上界   
  112.     //以物品单位重量价值递减序装填剩余容量   
  113.     while(i<=n && w[i]<=cleft)  
  114.     {  
  115.         cleft -= w[i];  
  116.         b += p[i];  
  117.         i++;  
  118.     }  
  119.   
  120.     //装填剩余容量装满背包   
  121.     if(i<=n)  
  122.     {  
  123.         b += p[i]/w[i]*cleft;  
  124.     }  
  125.   
  126.     return b;  
  127. }  
  128.   
  129. //将一个活节点插入到子集树和优先队列中   
  130. template<class Typew,class Typep>  
  131. void Knap<Typew,Typep>::AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int lev)  
  132. {  
  133.     bbnode *b = new bbnode;  
  134.     b->parent = E;  
  135.     b->LChild = ch;  
  136.   
  137.     HeapNode<Typep,Typew> N;  
  138.     N.uprofit = up;  
  139.     N.profit = cp;  
  140.     N.weight = cw;  
  141.     N.level  = lev;  
  142.     N.ptr = b;  
  143.   
  144.     H->Insert(N);  
  145. }  
  146.   
  147. //优先队列式分支限界法,返回最大价值,bestx返回最优解   
  148. template<class Typew,class Typep>  
  149. Typep Knap<Typew,Typep>::MaxKnapsack()  
  150. {  
  151.     H = new MaxHeap<HeapNode<Typep,Typew>>(1000);  
  152.   
  153.     //为bestx分配存储空间   
  154.     bestx = new int[n+1];  
  155.   
  156.     //初始化   
  157.     int i = 1;  
  158.     E = 0;  
  159.     cw = cp = 0;              
  160.     Typep bestp = 0;//当前最优值   
  161.     Typep up = Bound(1);    //价值上界   
  162.   
  163.     //搜索子集空间树   
  164.     while(i!=n+1)  
  165.     {  
  166.         //检查当前扩展节点的左儿子节点   
  167.         Typew wt = cw + w[i];  
  168.         if(wt <= c)//左儿子节点为可行节点   
  169.         {  
  170.             if(cp+p[i]>bestp)  
  171.             {  
  172.                 bestp = cp + p[i];  
  173.             }  
  174.             AddLiveNode(up,cp+p[i],cw+w[i],true,i+1);             
  175.         }  
  176.   
  177.         up = Bound(i+1);  
  178.         //检查当前扩展节点的右儿子节点   
  179.         if(up>=bestp)//右子树可能含有最优解   
  180.         {  
  181.             AddLiveNode(up,cp,cw,false,i+1);  
  182.         }  
  183.   
  184.         //取下一扩展节点   
  185.         HeapNode<Typep,Typew> N;  
  186.         H->DeleteMax(N);  
  187.         E = N.ptr;  
  188.         cw = N.weight;  
  189.         cp = N.profit;  
  190.         up = N.uprofit;  
  191.         i = N.level;  
  192.     }  
  193.   
  194.     //构造当前最优解   
  195.     for(int j=n; j>0; j--)  
  196.     {  
  197.         bestx[j] = E->LChild;  
  198.         E = E->parent;  
  199.     }  
  200.     return cp;  
  201. }  
  202.   
  203. //返回最大价值,bestx返回最优解   
  204. template<class Typew,class Typep>  
  205. Typep Knapsack(Typep p[],Typew w[],Typew c,int n, int bestx[])  
  206. {  
  207.     //初始化   
  208.     Typew W = 0;    //装包物品重量   
  209.     Typep P = 0;    //装包物品价值   
  210.       
  211.     //定义依单位重量价值排序的物品数组   
  212.     Object *Q  = new Object[n];  
  213.     for(int i=1; i<=n; i++)  
  214.     {  
  215.         //单位重量价值数组   
  216.         Q[i-1].ID = i;  
  217.         Q[i-1].d = 1.0*p[i]/w[i];  
  218.         P += p[i];  
  219.         W += w[i];  
  220.     }  
  221.   
  222.     if(W<=c)  
  223.     {  
  224.         return P;//所有物品装包   
  225.     }  
  226.   
  227.     //依单位价值重量排序   
  228.     BubbleSort(Q,n);  
  229.   
  230.     //创建类Knap的数据成员   
  231.     Knap<Typew,Typep> K;  
  232.     K.p = new Typep[n+1];  
  233.     K.w = new Typew[n+1];  
  234.   
  235.     for(int i=1; i<=n; i++)  
  236.     {  
  237.         K.p[i]  = p[Q[i-1].ID];  
  238.         K.w[i] = w[Q[i-1].ID];  
  239.     }  
  240.   
  241.     K.cp = 0;  
  242.     K.cw = 0;  
  243.     K.c = c;  
  244.     K.n = n;  
  245.   
  246.     //调用MaxKnapsack求问题的最优解   
  247.     Typep bestp = K.MaxKnapsack();  
  248.     for(int j=1; j<=n; j++)  
  249.     {  
  250.         bestx[Q[j-1].ID] = K.bestx[j];  
  251.     }  
  252.   
  253.     delete Q;  
  254.     delete []K.w;  
  255.     delete []K.p;  
  256.     delete []K.bestx;  
  257.     return bestp;     
  258. }  
  259.   
  260. template<class Type>    
  261. void BubbleSort(Type a[],int n)    
  262. {    
  263.      //记录一次遍历中是否有元素的交换        
  264.      bool exchange;      
  265.      for(int i=0; i<n-1;i++)      
  266.      {      
  267.         exchange = false ;      
  268.         for(int j=i+1; j<=n-1; j++)      
  269.         {      
  270.             if(a[j]<=a[j-1])      
  271.             {      
  272.                 Swap(a[j],a[j-1]);     
  273.                 exchange = true;      
  274.             }       
  275.         }       
  276.         //如果这次遍历没有元素的交换,那么排序结束        
  277.         if(false == exchange)      
  278.         {    
  279.              break ;      
  280.         }    
  281.      }    
  282. }    
  283.     
  284. template <class Type>    
  285. inline void Swap(Type &a,Type &b)    
  286. {    
  287.     Type temp = a;    
  288.     a = b;    
  289.     b = temp;    
  290. }    
//0-1背包问题 分支限界法求解 
#include "stdafx.h"
#include "MaxHeap.h"
#include <iostream>
using namespace std;

class Object
{
	template<class Typew,class Typep>
	friend Typep Knapsack(Typep p[],Typew w[],Typew c,int n, int bestx[]);
	public:
		int operator <= (Object a) const
		{
			return d>=a.d;
		}
	private:
		int ID;
		float d;//单位重量价值
};

template<class Typew,class Typep> class Knap;

class bbnode
{
	friend Knap<int,int>;
	template<class Typew,class Typep>
	friend Typep Knapsack(Typep p[],Typew w[],Typew c,int n, int bestx[]);
	private:
		bbnode * parent;	//指向父节点的指针
		bool LChild;		//左儿子节点标识
};

template<class Typew,class Typep>
class HeapNode
{
	friend Knap<Typew,Typep>;
	public:
		operator Typep() const
		{
			return uprofit;
		}
	private:
		Typep uprofit,		//节点的价值上界
			  profit;		//节点所相应的价值
		Typew weight;		//节点所相应的重量
		int level;			//活节点在子集树中所处的层序号
		bbnode *ptr;		//指向活节点在子集中相应节点的指针
};

template<class Typew,class Typep>  
class Knap  
{  
	template<class Typew,class Typep>
	friend Typep Knapsack(Typep p[],Typew w[],Typew c,int n, int bestx[]);
	public:
		Typep MaxKnapsack();
    private:  
		MaxHeap<HeapNode<Typep,Typew>> *H;
        Typep Bound(int i);
		void AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int lev);

		bbnode *E;	//指向扩展节点的指针
        Typew c;    //背包容量  
        int n;      //物品数  
  
        Typew *w;   //物品重量数组  
        Typep *p;   //物品价值数组  
        Typew cw;   //当前重量  
  
        Typep cp;   //当前价值  
        int *bestx; //最优解  
};  

template <class Type>  
inline void Swap(Type &a,Type &b);  
  
template<class Type>  
void BubbleSort(Type a[],int n); 

int main()
{
	int n = 3;//物品数  
    int c = 30;//背包容量  
    int p[] = {0,45,25,25};//物品价值 下标从1开始  
    int w[] = {0,16,15,15};//物品重量 下标从1开始  
	int bestx[4];//最优解
  
    cout<<"背包容量为:"<<c<<endl;  
    cout<<"物品重量和价值分别为:"<<endl;  
  
    for(int i=1; i<=n; i++)  
    {  
        cout<<"("<<w[i]<<","<<p[i]<<") ";  
    }  
    cout<<endl;  
  
    cout<<"背包能装下的最大价值为:"<<Knapsack(p,w,c,n,bestx)<<endl;  
	cout<<"此背包问题最优解为:"<<endl;
	for(int i=1; i<=n; i++)
	{
		cout<<bestx[i]<<" ";
	}
	cout<<endl;
    return 0;  
}

template<class Typew,class Typep>
Typep Knap<Typew,Typep>::Bound(int i)//计算节点所相应价值的上界
{
	Typew cleft = c-cw;	//剩余容量高
	Typep b = cp;		//价值上界
	//以物品单位重量价值递减序装填剩余容量
	while(i<=n && w[i]<=cleft)
	{
		cleft -= w[i];
		b += p[i];
		i++;
 	}

	//装填剩余容量装满背包
	if(i<=n)
	{
		b += p[i]/w[i]*cleft;
	}

	return b;
}

//将一个活节点插入到子集树和优先队列中
template<class Typew,class Typep>
void Knap<Typew,Typep>::AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int lev)
{
	bbnode *b = new bbnode;
	b->parent = E;
	b->LChild = ch;

	HeapNode<Typep,Typew> N;
	N.uprofit = up;
	N.profit = cp;
	N.weight = cw;
	N.level  = lev;
	N.ptr = b;

	H->Insert(N);
}

//优先队列式分支限界法,返回最大价值,bestx返回最优解
template<class Typew,class Typep>
Typep Knap<Typew,Typep>::MaxKnapsack()
{
	H = new MaxHeap<HeapNode<Typep,Typew>>(1000);

	//为bestx分配存储空间
	bestx = new int[n+1];

	//初始化
	int i = 1;
	E = 0;
	cw = cp = 0;			
	Typep bestp = 0;//当前最优值
	Typep up = Bound(1);	//价值上界

	//搜索子集空间树
	while(i!=n+1)
	{
		//检查当前扩展节点的左儿子节点
		Typew wt = cw + w[i];
		if(wt <= c)//左儿子节点为可行节点
		{
			if(cp+p[i]>bestp)
			{
				bestp = cp + p[i];
			}
			AddLiveNode(up,cp+p[i],cw+w[i],true,i+1);			
		}

		up = Bound(i+1);
		//检查当前扩展节点的右儿子节点
		if(up>=bestp)//右子树可能含有最优解
		{
			AddLiveNode(up,cp,cw,false,i+1);
		}

		//取下一扩展节点
		HeapNode<Typep,Typew> N;
		H->DeleteMax(N);
		E = N.ptr;
		cw = N.weight;
		cp = N.profit;
		up = N.uprofit;
		i = N.level;
	}

	//构造当前最优解
	for(int j=n; j>0; j--)
	{
		bestx[j] = E->LChild;
		E = E->parent;
	}
	return cp;
}

//返回最大价值,bestx返回最优解
template<class Typew,class Typep>
Typep Knapsack(Typep p[],Typew w[],Typew c,int n, int bestx[])
{
	//初始化
	Typew W = 0;	//装包物品重量
	Typep P = 0;	//装包物品价值
	
	//定义依单位重量价值排序的物品数组
	Object *Q  = new Object[n];
	for(int i=1; i<=n; i++)
	{
		//单位重量价值数组
		Q[i-1].ID = i;
		Q[i-1].d = 1.0*p[i]/w[i];
		P += p[i];
		W += w[i];
	}

	if(W<=c)
	{
		return P;//所有物品装包
	}

	//依单位价值重量排序
	BubbleSort(Q,n);

	//创建类Knap的数据成员
	Knap<Typew,Typep> K;
	K.p = new Typep[n+1];
	K.w = new Typew[n+1];

	for(int i=1; i<=n; i++)
	{
		K.p[i]  = p[Q[i-1].ID];
		K.w[i] = w[Q[i-1].ID];
	}

	K.cp = 0;
	K.cw = 0;
	K.c = c;
	K.n = n;

	//调用MaxKnapsack求问题的最优解
	Typep bestp = K.MaxKnapsack();
	for(int j=1; j<=n; j++)
	{
		bestx[Q[j-1].ID] = K.bestx[j];
	}

	delete Q;
	delete []K.w;
	delete []K.p;
	delete []K.bestx;
	return bestp;	
}

template<class Type>  
void BubbleSort(Type a[],int n)  
{  
     //记录一次遍历中是否有元素的交换     
     bool exchange;    
     for(int i=0; i<n-1;i++)    
     {    
        exchange = false ;    
        for(int j=i+1; j<=n-1; j++)    
        {    
            if(a[j]<=a[j-1])    
            {    
                Swap(a[j],a[j-1]);   
                exchange = true;    
            }     
        }     
        //如果这次遍历没有元素的交换,那么排序结束     
        if(false == exchange)    
        {  
             break ;    
        }  
     }  
}  
  
template <class Type>  
inline void Swap(Type &a,Type &b)  
{  
    Type temp = a;  
    a = b;  
    b = temp;  
}  
     程序运行结果如图:




  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分支限界法是一种用来解决组合优化问题的算法,而0-1背包问题是其中一个经典的问题。在0-1背包问题中,我们有一系列物品,每个物品有自己的重量和价值,而我们有一个背包,要求在不超过背包承重的情况下,选择一些物品放入背包,使得放入背包的物品总价值最大。 在分支限界法中,我们通过不断地分支和剪枝的方来搜索最优解。首先,我们将问题空间分为若干个子空间,对这些子空间进行搜索;接着,对于每个子空间,我们计算出上界和下界,如果上界小于当前最优解,就可以放弃这个子空间;最后,我们不断地搜索子空间,直到所有的子空间都搜索完毕,得到最优解。 对于0-1背包问题,我们可以通过分支限界法来解决。首先,我们可以根据每个物品的单位重量价值来对物品进行排序,然后逐个尝试放入背包或不放入背包,每次都计算当前状态下的背包总价值和剩余空间能够放入的最大价值,将这些状态加入到搜索队列中。在搜索的过程中,我们不断地计算当前状态的上界和下界,并及时剪枝。最终,当搜索完所有的状态后,我们就可以得到0-1背包问题的最优解。 总的来说,分支限界法是一种高效的解决0-1背包问题算法,通过合理的状态空间分割和剪枝操作,可以大大减少搜索的时间复杂度,找到最优解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值