分支界限法 0-1揹包問題 java

問題:有N件物品和一個容量爲V的揹包。第i件物品的重量是w[i],價值是v[i]。求 解將哪些物品裝入揹包可使這些物品的重量總和不超過揹包容量,且價值總和最大。

思路:創建兩個類。第一個類是商品類。商品們做個預處理。全部放到一個列表裏。再按照性價比排序。還有是揹包類。裏面存放着,最大可能價值,還能存放的重量,還有其父親類。總價值等。然後我們開始遍歷。無非就兩種情況。放入和不放入。亂入狀態加個1,不放入狀態加個0.然後都要求個最大可能價值。得出價值的方式就是挺的放後面的數,放爆了就放把爆之前剩餘的體積乘與後一個商品的平均單價。
最後求出一組最大可能性。時間複雜度時間複雜度爲O(2^n)。

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

public class BagProblem 
{
    int[] price={10,14,20,9}; //每個東西的價格
    int[] weight={5,7,10,3};  //每個東西的重量
    int max=19;               //最多存儲重量
    List<Produce> list=new ArrayList<Produce>();//春芳商品的列表,按照價值從大到小排
    PriorityQueue<Bag> heap=new PriorityQueue<Bag>((a,b)->{return (b.maxPrice-a.maxPrice)==0?b.reWeight-a.reWeight:b.maxPrice-a.maxPrice;});//存放當前揹包的狀態
    List<Bag> result=new ArrayList<Bag>();//存放結果
    BagProblem()
    {
        for(int i=0;i<weight.length;i++)
        {
            Produce produce=new Produce(price[i],weight[i],i);
            list.add(produce);
        }
        Collections.sort(list,(a,b)->b.bw-a.bw);

        Bag root=new Bag(max);//起點狀態
        getUpPrice(root,list);
        heap.add(root);
        while(!heap.isEmpty())
        {
            Bag temp=heap.poll();
            if(temp.i>=list.size()-1)
            {
                printAnswer(temp);
                break;
            }

            //不放入
            Bag notPut=new Bag(temp,temp.i+1);
            if(!notPut.boon)
            {
                getUpPrice(notPut, list);
                heap.add(notPut);
            }

            //放入
            Bag putIn=new Bag(temp,list.get(temp.i+1),temp.i+1);
            if(!putIn.boon)
            {
                getUpPrice(putIn, list);
                heap.add(putIn);
            }   
        }
    }

    //獲得最大價值
    private void getUpPrice(Bag tempBag,List<Produce> list)
    {
        int re=tempBag.reWeight;
        for(int i=tempBag.i+1;i<list.size();i++)
        {
            int temp=re-list.get(i).weight;
            if(temp>=0)
            {
                re=temp;
                tempBag.maxPrice+=list.get(i).price;
            }else
            {
                tempBag.maxPrice+=list.get(i).price/list.get(i).weight*re;
                break;
            }
        }
    }
    private void printAnswer(Bag temp)
    {
        for(int i=0;i<list.size();i++)
        {
            if(temp.stute.charAt(i)=='1')
                System.out.println("放入價值爲"+list.get(i).price+",重量爲 "+list.get(i).weight+"的商品");
        }
    }
    public static void main(String[] argc)
    {
        BagProblem test=new BagProblem();
    }
}
//定義揹包類
class Bag
{
    int sumPrice;  //揹包內的總價格
    int reWeight; //揹包內的剩餘
    int maxPrice;//最大價值
    int max;      //最大承載重量
    int i;        //當前商品的序列值
    boolean boon=false;//是否重量是否爆炸
    String stute;
    Bag father;   //前一個揹包的狀態
    Bag(){}
    //初始狀態包
    Bag(int max)
    {
        father=null;
        sumPrice=0;
        reWeight=max;
        this.max=max;
        this.i=-1;
        stute="";
    }
    //構建一個不放入該項的包
    Bag(Bag father,int i)
    {
        sumPrice=father.sumPrice;
        reWeight=father.reWeight;
        maxPrice=father.sumPrice;
        max=father.max;
        this.i=i;
        stute=father.stute+"0";
        this.father=father;
    }
    //構建一個放入的包
    Bag(Bag father,Produce produce,int i)
    {
        sumPrice=father.sumPrice+produce.price;
        reWeight=father.reWeight-produce.weight;
        maxPrice=father.sumPrice+produce.price;
        if(reWeight<0)
            boon=true;
        max=father.max;
        this.i=i;
        stute=father.stute+"1";
        //maxPrice 到時候會由getUpPrice後期算出來的
        this.father=father;
    }
}
//定義商品類
class Produce
{
    int id=0;
    int price;
    int weight;
    int bw;
    Produce(){}
    Produce(int price,int weight,int id)
    {
        this.id=id;
        this.price=price;
        this.weight=weight;
        bw=price/weight;
    }
}


這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章