7-1 0-1背包 (20 分)

给定n(n<=100)种物品和一个背包。物品i的重量是wi,价值为vi,背包的容量为C(C<=1000)。问:应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。

输入格式:

共有n+1行输入: 第一行为n值和c值,表示n件物品和背包容量c; 接下来的n行,每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。

输出格式:

输出装入背包中物品的最大总价值。

输入样例:

在这里给出一组输入。例如:

5 10
2 6
2 3
6 5
5 4
4 6

输出样例:

在这里给出相应的输出。例如:

15

这里采用回溯法,剪枝时以单位质量的价值大小新建一个数组b[],并以其大小为基准从大到小对b[]数组和物品数组a[][]进行排序,以方便确定叶结点上界;这里上界计算方法采用以当前背包价值value加上背包剩余容量乘上当前最大单位价值((c-weight)*b[i]);以b[]数组为基准同时对a[][]数组和b[]数组同时排序采用快排QuickSort的改写,具体算法如下:


package 宿題;
import java.io.*;

public class PTA0_1Bagpack {
  static int n;
  static int c;
  static double max=0;
  static double a[][];
  static double b[];
  public static void main(String args[])throws IOException{
    StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    in.nextToken();
    n=(int)in.nval;
    in.nextToken();
    c=(int)in.nval;
    a=new double[n][2];
    b=new double[n];
    for(int i=0;i<n;i++){
      for(int j=0;j<2;j++){
        in.nextToken();
        a[i][j]=(double)in.nval;
      }
      b[i]=a[i][1]/a[i][0];//计算单位质量价值,存入b[]数组;因为b[]数组为double,为防止后面出现double转int造成值丢失,这里数据都用double储存;
    }
    QuickSort(b,0,n-1);
    Count(a,0,0,0);
    System.out.println((int)max);//因为运算输出结果为Int,这里加一个强制转换;
  }

  private static void Count(double a[][],int i,double value,double weight){
    if(i==n){//递归结束,比较值大小;
      if(value>max)
        max=value;
    }else if(value+(c-weight)*b[i]>=max){//计算结点上界,如果上界小于当前最大值直接结束当前递归;
      if(a[i][0]+weight<=c)//结点分为取物品和不取两个,取物品时判断背包容量是否足够;
        Count(a,i+1,value+a[i][1],weight+a[i][0]);
      Count(a,i+1,value,weight);
    }
  }

  private static void QuickSort(double a[],int p,int r){//快排算法,在b[]数组值出现互换时同时互换a[][]数组对应的数值;
    if(p<r){
      int q=Partition(a,p,r);
      QuickSort(a,p,q-1);
      QuickSort(a,q+1,r);
    }
  }

  private static int Partition(double A[],int p,int r){
    int i=p,j=r+1;
    double x=A[p];
    double x0=a[p][0];
    double x1=a[p][1];
    while(true){
      while(A[++i]>x&&i<r);
      while(A[--j]<x);
      if(i>=j)
        break;
      Swap(i,j);
    }
    A[p]=A[j];
    a[p][0]=a[j][0];
    a[p][1]=a[j][1];
    A[j]=x;
    a[j][0]=x0;
    a[j][1]=x1;
    return j;
  }

  private static void Swap(int i,int j){
    double a1=a[i][1];
    double a0=a[i][0];
    double b0=b[i];
    a[i][1]=a[j][1];
    a[i][0]=a[j][0];
    b[i]=b[j];
    a[j][1]=a1;
    a[j][0]=a0;
    b[j]=b0;
  }

}

该算法在最坏情况下的时间复杂度为O(2^n)。

 

猜你喜欢

转载自www.cnblogs.com/Modori/p/11929375.html