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

給定n(n<=100)種物品和一個揹包。物品i的重量是wi,價值爲vi,揹包的容量爲C(C<=1000)。問:應如何選擇裝入揹包中的物品,使得裝入揹包中物品的總價值最大? 在選擇裝入揹包的物品時,對每種物品i只有兩個選擇:裝入或不裝入。不能將物品i裝入屢次,也不能只裝入部分物品i。java

輸入格式:

共有n+1行輸入: 第一行爲n值和c值,表示n件物品和揹包容量c; 接下來的n行,每行有兩個數據,分別表示第i(1≤i≤n)件物品的重量和價值。算法

輸出格式:

輸出裝入揹包中物品的最大總價值。數組

輸入樣例:

在這裏給出一組輸入。例如:ui

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

輸出樣例:

在這裏給出相應的輸出。例如:code

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)。it

相關文章
相關標籤/搜索