揹包筆記及Java實現

推薦揹包九講,很是棒。如下是我的對其前四講內容的梳理和Java實現,用於快速回顧知識點。java

01揹包

問題:算法

N件物品,一個容量M的揹包。A[]是物品體積,V[]是物品價值,求揹包能裝物品的最大價值。

思路:數組

dp[i][j]表前i件物品在容量最大爲j的限制下能獲得的最大價值。

圖片描述

public int pack01Solution1(int m,int A[],int V[] ){
        int[][] dp = new int[A.length+1][m+1];
        for(int i=0;i<A.length;i++){
            for(int j=0;j<=m;j++){
                if(A[i]>j)dp[i+1][j] = dp[i][j];
                else dp[i+1][j] = Math.max(dp[i][j],dp[i][j-A[i]]+V[i]);
            }
        }
        return dp[A.length][m];
    }

時間複雜度O(NM),空間複雜度O(NM)。優化

空間優化爲O(M):spa

public int pack01Solution2(int m,int A[],int V[] ){
        int[]dp = new int[m+1];
        for(int i=0;i<A.length;i++){
            for(int j=m;j>=A[i];j--){
                dp[j] = Math.max(dp[j],dp[j-A[i]]+V[i]);
            }
        }
        return dp[m];
    }

能夠把01揹包中對一件物品的處理抽取爲方法:code

public void ZeroOnePack(int cost,int value,int[] dp,int m){
        for(int j=m;j>=cost;j--)
            dp[j] = Math.max(dp[j],dp[j-cost]+value);
    }

初始化的細節問題:blog

clipboard.png

徹底揹包問題

問題:圖片

N種物品,揹包容量爲M,每種無限件,給出物品體積和價值A[]、V[],求最大價值。

思路:ip

dp[i][j] = max{dp[i-1][j-k*A[i]]+k*V[i]|0<=k*A[i]<=M}

時間複雜度:有O(NM)個狀態,每一個狀態求解時間O(M/A[i]),總時間O(Σ(M/A[i])*M).

轉化爲01揹包問題:get

-第i種物品轉化爲M/A[i]件體積和價值不變的物品,複雜度不變
-第i種物品表示成2^k件物品的總和,A[i]*(2^k)<=M,每種物品可拆成O(logM/A[i])件物品
-一維數組實現的**O(NM)**算法:dp[i][j] = max{dp[i-1][j],dp[i][j-A[i]]+V[j]}
public int packComSolution(int m,int[] A,int[] V){
        int[] dp = new int[m+1];
        for(int i=0;i<A.length;i++){
            for(int j=A[i];j<=m;j++)
                dp[j] = Math.max(dp[j],dp[j-A[i]]+V[i]);
        }
        return dp[m];
    }

其中處理一種徹底揹包的物品能夠抽取方法:

public  void CompletePack(int cost,int value,int[] dp,int m){
        for(int j=cost;j<=m;j--)
            dp[j] = Math.max(dp[j],dp[j-cost]+value);
    }

多重揹包

問題:

在01揹包基礎上,增長條件每件物品的可取件數n[];

思路:

轉化成01揹包,每種物品的n[i]均可以用2^0,2^1,..2^(k-1),n-(2^k-1)中若干數的和表示,k是知足n[i]-2^k+1>0的最大整數。
第i種物品分紅了O(log n[i])種物品,複雜度從O(M*Σn[i])變爲O(M* Σlog n[i])
public void packMutiSolutionk(int m,int[] A,int[] V ,int[] N){
        int[] dp = new int[m+1];
        for(int i=0;i<A.length;i++){
            MutiPack(A[i],V[i],N[i],dp,m);
        }
    }
    public void MutiPack(int cost, int value, int amount, int[] dp, int m){
        if(cost*amount>=m){
            CompletePack(cost,value,dp,m);
            return;
        }
        int s=1;
        while(s<amount){//條件:amount-s>0
            ZeroOnePack(s*cost,s*value,dp,m);
            amount -= s;
            s *= 2;
        }
        ZeroOnePack(amount*cost,amount*value,dp,m);
    }

混合揹包

clipboard.png

相關文章
相關標籤/搜索