1. 程式人生 > >0-1揹包問題-動態規劃

0-1揹包問題-動態規劃

    揹包問題可以使用動態規劃獲得最優解,動態規劃的思路是:通過獲得單階段的最優解後,升級到多階段,每次升級時都使用上一階段的最優解計算,避免遍歷所有可能時產生的時間消耗。

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Created by saishangmingzhu on 2018/11/27.
 */
public class Rucksack {
    //【1】輸入揹包容量
    //【2】輸入物品體積及價值
    public static void main(String[] arg) {
        new Rucksack().dynamic();
    }


    /**
     * 動態規劃
     【1】定義表格,物品體積的最大公約數作為列的步長求出最短列,物品作為行
     【2】定義物品,名稱、體積、價值
     */
    public void dynamic(){
        int rucksackV=10;
        List<Goods> goodsList=new ArrayList<>();
        int i=0;
        goodsList.add(i++,new Goods("0",0,0));//方便構建表格使用,無業務意義
        //測試最大公約數為1的情況
        goodsList.add(i++,new Goods("書",1,2));
        goodsList.add(i++,new Goods("足球",3,4));
        goodsList.add(i++,new Goods("大箱子",7,2));
        goodsList.add(i++,new Goods("macbook",3,6));
        goodsList.add(i++,new Goods("iphone",1,5));
        goodsList.add(i++,new Goods("禮盒",5,3));
        goodsList.add(i++,new Goods("小箱子",4,2));

//        //測試最大公約數為2的情況
//        goodsList.add(i++,new Goods("書",2,2));
//        goodsList.add(i++,new Goods("足球",4,4));
//        goodsList.add(i++,new Goods("大箱子",8,2));
//        goodsList.add(i++,new Goods("macbook",6,6));
        int step=getGCD(goodsList,rucksackV);
        //表格中第0行,第0列無業務意義,使用的意義是不需要在後續表格使用中判斷座標越界,用空間換時間
        int colum=rucksackV/step+1;
        int[][] table=new int[i][colum];
        for (int m=1;m<goodsList.size();m++){
            Goods goods=goodsList.get(m);
            for (int n=1;n<colum;n++){
                //確保當前物品單獨可以放入揹包
                table[m][n]=table[m-1][n];
                int surplus=n*step-goods.getVolume();
                if (surplus>=0){
                    int worth=goods.getWorth()+table[m-1][surplus/step];
                    if (worth>table[m-1][n]){
                        table[m][n]=worth;
                    }
                }
            }

        }

        for (int m=1;m<table.length;m++){
            for (int n=1;n<table[m].length;n++){
                if (table[m][n]<10)
                    System.out.print(" "+table[m][n]+",");
                else
                    System.out.print(table[m][n]+",");
            }
            System.out.println();
        }
    }

    /**
     * 求解最大公約數
     * @param goodsList
     * @param rucksackV
     * @return
     */
    public int getGCD(List<Goods> goodsList,int rucksackV){
        int minV=rucksackV;
        int[] vs=new int[goodsList.size()-1];//-1為去除沒有業務意義的第一個
        for (int i=0;i<goodsList.size()-1;i++){
            vs[i]=goodsList.get(i+1).getVolume();
            if (vs[i]<minV){
                minV=vs[i];
            }
        }
        boolean flag=true;
        while (minV>1){
            for (int v:vs){
                if(v%minV!=0){
                    flag=false;
                    break;
                }
            }
            if (flag){
                break;
            }
            minV--;
        }
        return minV;
    }
}
class Goods{
    private String name;
    private int volume;
    private int worth;

    public Goods(){}
    public Goods(String n,int v,int w){
        this.name=n;
        this.volume=v;
        this.worth=w;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getVolume() {
        return volume;
    }

    public void setVolume(int volume) {
        this.volume = volume;
    }

    public int getWorth() {
        return worth;
    }

    public void setWorth(int worth) {
        this.worth = worth;
    }
}