1. 程式人生 > >演算法學習——貪心演算法之可拆揹包

演算法學習——貪心演算法之可拆揹包

演算法描述

已知道n種物品和一個可容納c重量的揹包,第i種物品的重量為wi,價值為pi,裝包的時候可以把物品拆開(即可只裝每種物品的一部分),設計如何裝包,使裝包所得整體的價值最高?

演算法思路

  1. 首先,我們要知道,n種物品以及他們對應的價值,都是由使用者輸入的

  2. 我們使用貪心演算法,每一步取最大效益的物品放入揹包之中(及單位價值為最高的物品 單位價值=pi/wi)

  3. 由以上思路,我們可以定義一個二維陣列來接收使用者輸入的數值

    w[i][0] 代表了第i種物品的重量(即wi)

    w[i][1] 代表了第i種物品的價值(即pi)

    w[n][m] n範圍為1~n m範圍為0~1

    這裡需要注意,陣列下標是從0開始的,我們的n是從1開始的,空出了一個0,所以我們定義n應該定義為n+1 這裡應該不難理解,n+1的話,下標就是0~n,我們需要1~n這n個位置

    定義為double[][] w = new double[n+1][2]

  4. 除了上面所說,我們還需一個Flag類來存放單位價值以及該單位價值對應的第i個物品(也就是下標)

  5. 我們將單位價值計算得出後作為Flag類成員變數content,以及下標作為Flag類中的成員變數flag,之後使用ArrayList存放多個Flag類

  6. 之後,將單位價值存放在一個一維陣列中,使用排序,從小到大排序

  7. 得到排序之後的一維陣列,依次與ArrayList中的每一個Flag類content作比較,得到其對應的下標,存入到棧中

  8. 之後,棧頂就是單位價值最大的所對應的下標,依次取出來(即實現了每次都是取到的物品都是單位價值最大的),進行相關的運算即可

演算法實現

    Scanner scanner = new Scanner(System.in);
    double cost = 0;//記錄當揹包滿的時候所達到的價值
    System.out.println("輸入物品個數n:");
    int n = scanner.nextInt();
    System.out.println("輸入揹包可裝容量c:");
    double c = scanner.nextDouble();
    double temp[] = new double[n+1];
    double w[][] = new double[n+1][2];
    
    ArrayList<Flag> list = new ArrayList<Main.Flag>();
    for(int i=1;i<=n;i++){
        System.out.println("w"+i+"重量:");
        w[i][0] = scanner.nextDouble();
        System.out.println("w"+i+"價值:");
        w[i][1] = scanner.nextDouble();
        temp[i]=w[i][1]/w[i][0];
    }
    scanner.close();
    
    Stack<Integer> stack = new Stack<Integer>();
    
    //存入到list中,儲存原來的下標和內容
    for(int i=1;i<temp.length;i++){
        
        Flag flag = new Flag(i, temp[i]);
        list.add(flag);
        
    }
    
    double t = 0;
    
    Arrays.sort(temp);//使用java中自帶的快速排序
    
    //將原來的下標存入進棧中,處於棧頂的是單位價值最高的該物品的下標
    for(int i=1;i<temp.length;i++){
        for(Flag flag : list){
            if(flag.getContent()==temp[i]){
                stack.push(flag.getFlag());
            }
        }
    }
    
    while(!stack.isEmpty()){
        int i =stack.pop();//出棧
        c = c -w[i][0];
        if(c<=0){
            c = c+w[i][0];//加回之前所減去的內容,計算百分比
            double a = (c/w[i][0])*100;
            DecimalFormat format = new DecimalFormat("##.#");
            System.out.println("裝入"+"第"+i+"種物品的百分之"+format.format(a)+",重量為"+w[i][0]+",價值為"+w[i][1]);
            cost = cost+w[i][1]*(a/100);
            System.out.println("最大價值為"+format.format(cost));
            break;
        }else{
            cost = cost+w[i][1];
        }
        
        System.out.println("裝入"+"第"+i+"種物品"+",重量為"+w[i][0]+",價值為"+w[i][1]);
        
        
    }
    
    
}

//定義了一個Flag類,存放原來的座標以及單位價值
public static class Flag{
    int flag;
    double content;
    public Flag(int flag,double content){
        this.flag = flag;
        this.content= content;
    }
    public int getFlag(){
        return this.flag;
    }
    public double getContent(){
        return this.content;
    }
} 

結果