回溯法实现01背包问题

                     回溯法实现01背包问题(递归版)

    老师今天让我们上机实验做这个,还是有点把握的。毕竟认真听课了嘛。回溯法其实就是套公式(个人理解)。

  来自清华大学出版社的《算法与分析》的解题步骤

   (1) 针对所给问题,定义问题的解空间;

   (2)确定易于搜索的解空间结构(解空间树);

   (3)以深度优先的方式搜索解空间树,并且在搜索过程中用剪枝函数避免无效搜索;

 

直接贴代码了,里面有较为详细的注释~

 

package bag;

import java.text.DecimalFormat;
import java.util.Arrays;

public class bagTest {
     public static void main(String []args){
         double c=20;
           int n=10;
           double []weight={5,5,3,4,5,1,2,4,3,2};
           double []value={5,4,3,2,1,10,1,5,4,3};
          
          /* double []weight=new double[n];
           double []value=new double[n];
           
           for(int i=0;i<n;i++){
               普通双精度随机数
               * double random1=Math.random()*100;
              double random2=Math.random()*100;  
               //只有两位小数的双精度数
              double random1=(double)Math.round((Math.random()*10+1)*100)/100;
              double random2=(double)Math.round((Math.random()*10+1)*100)/100;
              weight[i]=random1;
              value[i]=random2;
           }*/
           
           bag b=new bag(c,n,weight,value);
           
       }
}

class bag{
    
    private double c;
    private int n;
    
    private double []weight;
    private double []value;
    
    //存储排序后的编号
    private int []x;
    //最终选择的物品组
    private StringBuffer result;
    
    //完整解(最大价值)
    private double max;
    //部分解(当前最大值)
    private double pv;
    //当前重量
    private double pw;
 
    
    public bag(double c ,int n,double []weight, double []value){
         this.c=c;;
         this.n=n;
         this.weight=weight;
         this.value=value;
        
         x=new int[n];
         result=new StringBuffer();
         max=0;
         pv=0;
         pw=0;

         sort();
         backtrack(0);
    }
    

    private void sort() {

        Element[] e = new Element[n];
        for (int i = 0; i < n; i++) {
            e[i] = new Element(value[i], weight[i], i);
        }
        Arrays.sort(e);
      
        // 将排好序的物品按顺序重新放入value,weight
        for (int i = 0; i < n; i++) {
            x[i]=e[i].getI();  
            value[i] = e[i].getV();
            weight[i] = e[i].getW();

        }
        //测试排序是否正确
         for(int i=0;i<n;i++)
              System.out.println(x[i]+”   “+value[i] +”  “+    weight[i]);
    }
    
    
    private void backtrack(int t){
         if(t>n-1){max=pv; print(); return;}
         else{
             if(bound(t)){
                 if(constraint(t)){
                     pv+=value[t];
                     pw+=weight[t];
                     result.append(x[t]+” “);
                     backtrack(t+1);
                    
                 }else{
                    return;
                 }
             }else{
                 backtrack(t+1);
             }
         }
    }

   //打印选择的物品
    private void print() {
        DecimalFormat df=new DecimalFormat(“.##”);
        String st=df.format(max);
        System.out.println(” 总价值为:”+st+” 选取的物品序号分别是:”+result);
        
    }
   
    //剪枝函数(当“当前价值”+“剩余其他物品的总价值”<=”当前最优解”,就不用递归下去了)
    private boolean constraint(int t) {
        double vResidue=0;
        for(int i=t+1;i<n;i++){
             vResidue+=value[i];
         }
       
         if(max>=(pv+vResidue)) return false;
         
        return true;
    }
    
  //限界函数(“剩余背包容量”<0,就不用递归下去了)
    private boolean bound(int t) {
        //总容量-当前重量和即将放入背包物品的重量=剩余背包容量
        double wResidue=c-pw-weight[t];
        System.out.println(wResidue);
         if(wResidue<0)return false;
        return true;
    }
}

//制定 元素类,保存旧编号,价值,重量
class Element implements Comparable{
 private int i;
 private double  w,v;

 public Element(double v,double w,int i){
  this.w=w;
  this.v=v;
  this.i=i;
}

 public double getW() {
  return w;
 }

 public int getI() {
  return i;
 }

  public double getV() {
   return v;
  }

//从大到小排序
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
double vw=((Element)o).getV()/((Element)o).getW();
double tvw=this.getV()/this.getW();
if(tvw<vw) return 1;
if(tvw==vw) return 0;
return -1;
}

}

 

———————————————————————————–                 升级版                        —————————————————————————————————–

同样是根据价值比排列,这次只排列编号,其他保持不动

 

 

package bag;

import java.text.DecimalFormat;
import java.util.Arrays;

public class bagT {

     public static void main(String []args){
         double c=20;
           int n=10;
           /* 测试用例
             * double []weight={5,5,3,4,5,1,2,4,3,2};
               double []value={5,4,3,2,1,10,1,5,4,3};
          */
           double []weight=new double[n];
           double []value=new double[n];
           
           for(int i=0;i<n;i++){
            /*   普通双精度随机数
               * double random1=Math.random()*100;
              double random2=Math.random()*100;  */
               //只有两位小数的双精度数
              double random1=(double)Math.round((Math.random()*10+1)*100)/100;
              double random2=(double)Math.round((Math.random()*10+1)*100)/100;
              weight[i]=random1;
              value[i]=random2;
           }
           
           bag1 b=new bag1(c,n,weight,value);
           
       }
}

class bag1{
    
    private double c;
    private int n;
    
    private double []weight;
    private double []value;
    
    private double []perPrice;
    //存储排序后的编号
    private int []x;
    //最终选择的物品组
    private StringBuffer result;
    
    //完整解(最大价值)
    private double max;
    //部分解(当前最大值)
    private double pv;
    //当前重量
    private double pw;
 
    
    public bag1(double c ,int n,double []weight, double []value){
         this.c=c;;
         this.n=n;
         this.weight=weight;
         this.value=value;
        
         x=new int[n];
         for(int i=0;i<n;i++)
             x[i]=i;;
         perPrice=new double[n];
         for(int i=0;i<n;i++)
             perPrice[i]=value[i]/weight[i];
            
         result=new StringBuffer();
         max=0;
         pv=0;
         pw=0;
         
        
        
        
         sort(0,n-1);
        
        /* //测试排序是否正确
         for(int i=0;i<n;i++){
             int j=x[i];
               System.out.println(j+”   “+value[j] +”  “+    weight[j]+”  “+    perPrice[i]);
         }*/
         backtrack(0);
    }
    
    private void sort(int l,int r) {
        // TODO Auto-generated method stub
        if(l<r){
            int q=position(l,r);
            sort(l,q-1);
            sort(q+1,r);
        }
    }
   private int position(int l,int r){
       int i=l,j=r+1;
       double a=perPrice[l];
       int b=x[l];
         while(true){
            
             while(perPrice[++i]>a&&i<r);
             while(j>l&&perPrice[–j]<a);
             if(i>=j)break;
             double t1=perPrice[i];
             perPrice[i]=perPrice[j];
             perPrice[j]=t1;
            
             int t2=x[i];
             x[i]=x[j];
             x[j]=t2;
         }
         perPrice[l]=perPrice[j];
         perPrice[j]=a;
         x[l]=x[j];
         x[j]=b;
        return j;
        
    }
   
   private void backtrack(int t){
         if(t>n-1){max=pv; print(); return;}
         else{
             if(bound(t)){
                 if(constraint(t)){
                     pv+=value[x[t]];
                     pw+=weight[x[t]];
                     result.append(x[t]+” “);
                     backtrack(t+1);
                    
                 }else{
                    return;
                 }
             }else{
                 backtrack(t+1);
             }
         }
    }

   //打印选择的物品
    private void print() {
        DecimalFormat df=new DecimalFormat(“.##”);
        String st=df.format(max);
        System.out.println(” 总价值为:”+st+” 选取的物品序号分别是:”+result);
        
    }
   
    //剪枝函数(当“当前价值”+“剩余其他物品的总价值”<=”当前最优解”,就不用递归下去了)
    private boolean constraint(int t) {
        double vResidue=0;
        for(int i=t+1;i<n;i++){
             vResidue+=value[x[t]];
         }
       
         if(max>=(pv+vResidue)) return false;
         
        return true;
    }
    
  //限界函数(“剩余背包容量”<0,就不用递归下去了)
    private boolean bound(int t) {
        //总容量-当前重量和即将放入背包物品的重量=剩余背包容量
        double wResidue=c-pw-weight[x[t]];
        System.out.println(wResidue);
         if(wResidue<0)return false;
        return true;
    }
}

    原文作者:回溯法
    原文地址: https://blog.csdn.net/Pabebe/article/details/78734538
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞