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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM