0-1背包问题 --分支限界法--完整代码---(输出每一个结点状态)

改动了 Tyler_Zx0-1 背包问题的 4 种解决方法&&算法策略的分支限界,输入程序的详细步骤!

在这里插入图片描述
这里先贴上结果图! 详情向下看!
(请忽略我这对的有点不齐)
(过程中有注释,添加的代码都有标注)
下面是完整的源码

/

#include<iostream>
#include<algorithm>
using namespace std;

#define N 100//最多可能的物体数


struct  goods //1.物品结构体
{
	int sign;//物品的序号 
	int w;//物品的重量 
	int p;//物品的价值 
	 
 } a[N];
  
  
  
  bool m(goods a,goods b) //2.比较单位重量价值谁更大 
  {
  	return (a.p/a.w)>(b.p/b.w); 
   } 
   
   
   int max(int a,int b)//3.比较大小 
   {
   	return a<b?b:a; 
	} 
	
	
	
	
	
	int n,C,bestP=0,cp=0,cw=0;//n为物品个数  C为背包容量	                          
	int X[N],cx[N];
	
	
	struct KNAPNODE  //4.状态结构体
	{
		bool s1[N];//当前放入物品 
		int k;//搜索的深度
		int b; //价值上界,背包价值+剩下的最大单位重量价值的物品装满剩余容量的价值和
		int w;//物品重量
		int p;//物品价值 
	 } ;
	 
	 
	 
	 
	 
	 /5.堆 
	 struct HEAP  //堆元素结构体
	 {
	 	KNAPNODE *p;;//结点数据
		 int b;//所指结点的上界 
	  } ;
	 
	 
	//交换两个堆元素
	void  swap(HEAP  &a,HEAP &b)
	{
		HEAP  temp=a;
		a=b;
		b=temp; 
	 } 
	 
	 //堆中元素上移
	 void mov_up(HEAP H[],int i)
	 {
	 	bool  done=false;
		 if(i!=1)
		 {
		 	while(!done && i!=1)
			 {
			 	if(H[i].b>H[i/2].b)
				 {
				 	swap(H[i],H[i/2]) ;
				  } 
				  else{
				  	done =true; 
				  } 
				  i=i/2;
				   
			  } 
		  } 
	  } 
	 //堆中元素下移
void mov_down(HEAP H[], int n, int i)
{
    bool done = false;
    if((2*i)<=n)
    {
        while(!done && ((i = 2*i) <= n))
        {
            if(i+1 <= n && H[i+1].b > H[i].b)
            {
                i++;
            }
            if(H[i/2].b < H[i].b)
            {
                swap(H[i/2], H[i]);
            }
            else
            {
                done = true;
            }
        }
    }
}
 
//往堆中插入结点
void insert(HEAP H[], HEAP x, int &n)
{
    n++;
    H[n] = x;
    mov_up(H,n);
}
 
//删除堆中结点
void del(HEAP H[], int &n, int i)
{
    HEAP x, y;
    x = H[i]; y = H[n];
    n --;
    if(i <= n)
    {
        H[i] = y;
        if(y.b >= x.b)
        {
            mov_up(H,i);
        }
        else
        {
            mov_down(H, n, i);
        }
    }
}
 
//获得堆顶元素并删除
HEAP del_top(HEAP H[], int&n)
{
    HEAP x = H[1];
    del(H, n, 1);
    return x;
}
 
 /堆
  

 
//6.计算分支节点的上界,更新这个结点的上界  node.b 
void bound( KNAPNODE* node,int M, goods a[], int n)
{
    int i = node->k;
    float w = node->w;
    float p = node->p;
    if(node->w > M)
    {        //物体重量超过背包载重量
       node->b = 0;       //上界置为0
    }
    else
    {   
    多加了一个判断条件这里888888888888888888888888888
	if(node->s1[node->k]!=false)
     {
	
        while((w+a[i].w <= M)&&(i < n))
        {  
           w += a[i].w;   //计算背包已装入载重
           p += a[i++].p; //计算背包已装入价值
        }
        if(i<n)//判断是否是最后一个物品 
        {
           node->b = p + (M - w)*a[i].p/a[i].w;//不是,计算新的上界 
        }
        else
        {
           node -> b = p;//已经得到最终结果 
        }
    }
    多加, node->s1[node->k]==false的时候 8888888888888888888
    else{
    	if(i<n)//判断是否是最后一个物品 
        {
           node->b = p + (M - w)*a[i].p/a[i].w;//不是,计算新的上界 
        }
        else
        {
           node -> b = p;//已经得到最终结果 
        }
    	
	}
    
    
    }
}
 
 
 
 
//7.用分支限界法实现0/1背包问题
int KnapSack(int n,goods a[],int C, int X[])
{
    int i, k = 0;                 //堆中元素个数的计数器初始化为0
    int v;
    KNAPNODE *xnode, *ynode, *znode; //状态
	 
    HEAP x, y, z, *heap;  //堆结构体 
    
    heap = new HEAP[n*n];         //分配堆的存储空间
    
    
    
    for(i = 0; i < n; i++)
    {
       a[i].sign=i;               //记录物体的初始编号
    }
    
    
    sort(a,a+n,m);                //对物体按照价值重量比排序
    
    
    
    
    
    xnode = new KNAPNODE; //建立父亲结点,初始化 
    
    for(i = 0; i < n; i++)
    {          //初始化结点,表示没有放入背包 
       xnode->s1[i] = false;
    }
    
    xnode->k = xnode->w = xnode->p = 0;//全部初始化为0 
    /8888888888888888888888888  
     bound(xnode, C, a, n);     //计算结点x的上界
    cout<<"w: "<<xnode->w;
    cout<<"   v:"<<xnode->p;
	cout<<"   ub:"<<xnode->b; 
	cout<<"   input pt"<<endl;
	/888888888888888888888888 
    
    
    
    
    
    while(xnode->k < n) //还有物品需要判断 
    {   	
       ynode = new KNAPNODE;      //建立结点y
       *ynode = *xnode;           //结点x的数据复制到结点y,也就是全都初始化成0 
                            //也就是y是第一个结点了 
       
       
/8888888888888888888888888     
	    if(ynode->b!=0) 
	    {
	    cout<<"w: "<<ynode->w;
        cout<<"   v:"<<ynode->p;
        cout<<"   ub:"<<ynode->b; 
	   cout<<"   output"<<endl; 
        }  
        else
		{
		xnode->k++; 
		continue;	
		 }  
 /8888888888888888888888888
     
    
       ynode->s1[ynode->k] = true;    //装入第k个物体,第一次装入第0个物体 
       ynode->w += a[ynode->k].w;     //背包中物体重量累计
       ynode->p += a[ynode->k].p;     //背包中物体价值累计
       
       
       
       ynode->k++;               //搜索深度++
       bound(ynode, C, a, n);     //计算结点y的上界,更新y的y.b 
       
       y.b = ynode->b;  //更新pt表中的,也就是优先队列 堆中的数据 
       y.p = ynode;
      
 /888888888888888888888888888888888     
       //更新之后,将y结点加入pt表中 
       if(y.b!=0)
       {
        cout<<"w:"<< ynode->w;
	   cout<<"   v:"<<  ynode->p;
	   cout<<"    ub: "<< y.b;   
	   cout<<"   input pt"<<endl;  
	    }
/8888888888888888888888888888888888	   
        insert(heap, y, k);       //结点y按上界的值插入堆中
        
        
        
        
      
    	//不装入第k个物体    
       znode = new KNAPNODE;      //建立结点z
       *znode = *xnode;           //结点x的数据复制到结点z
       
       //测试(忽略):cout<<"zonode w  he p:  "<<znode->w<<znode->p<<znode->k<<endl;     
        //测试(忽略):ynode->s1[ynode->k] = true;  
       znode->s1[znode->k]=false;//不装入物品           
       znode->k++;                //搜索深度++
             
       bound(znode, C, a, n);     //计算节点z的上界
       
       //测试(忽略):cout<<"znode.b"<<znode->b;
       z.b = znode->b;
       z.p = znode;
                                 
       insert(heap, z, k);        //结点z按上界的值插入堆中 
       
 //8888888888888888888888888      
       if(z.b!=0)
       {
        cout<<"w:"<< znode->w;
	   cout<<"   v:"<<  znode->p;
	   cout<<"    ub: "<< z.b;   
	   cout<<"   input pt"<<endl;  
       }
//88888888888888888888888888888888	         
       delete xnode;
       x = del_top(heap, k);      //获得堆顶元素作为新的父亲结点
       xnode = x.p;	      
    }
     
    v = xnode->p;
    for(i = 0; i < n; i++)
    {          //取装入背包中物体在排序前的序号
    
	  
        if(xnode->s1[i])
        {
           X[a[i].sign] =1 ;
             
        }
        else
        {
           X[a[i].sign] = 0;
          
        }
    }
    delete xnode;
    delete heap;
    return v;                    //返回背包中物体的价值
}
 
/*测试以上算法的主函数*/
int main()
{
    goods b[N];
    printf("物品种数n: ");
    scanf("%d",&n);           //输入物品种数
    printf("背包容量C: ");
    scanf("%d",&C);           //输入背包容量
    for (int i=0;i<n;i++)     //输入物品i的重量w及其价值v
    {
       printf("物品%d的重量w[%d]及其价值v[%d]: ",i+1,i+1,i+1);
       scanf("%d%d",&a[i].w,&a[i].p);
       b[i]=a[i];
    }
 
    int sum=KnapSack(n,a,C,X);//调用分支限界法求0/1背包问题
    printf("分支限界法求解0/1背包问题:\nX=[ ");
    for(int i=0;i<n;i++)
       cout<<X[i]<<" ";//输出所求X[n]矩阵
    printf("]  装入总价值[%d]\n",sum);
    return 0;

}
	 
	 



  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值