01揹包問題的空間優化

oj地址:01揹包
首先說一下這道題引發的思考,我習慣把狀態轉移方程稱作小單元,它一般是以一個單元格爲計算單位的遞推過程,然後在小單元之上,我又把行與行之間的關係,稱作大單元。很多動態規劃的題,一個單元格一般依賴於其他幾個單元格,這是從單元格的角度上去看問題,如果從行的角度去看問題,很多的都是一行上的數據,只會依賴固定的一行或者幾行,這裏就是空間優化的出發點。比如一個二維表的空間是O(mn)的,而發現其第i行永遠只依賴第i-1行,那麼就可以只給它分配兩行,然後循環使用。
1.最初始的解決方法。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext()){
            int C=sc.nextInt();
            int N=sc.nextInt();
            int[] V=new int[N+1];//評價
            int[] P=new int[N+1];//價格
            int[][] dp=new int[N+1][C+1];//表示dp[i][j]表示前i件放入容量爲j的揹包時的最大評價
 
            for(int i=1;i<=N;i++){
                P[i]=sc.nextInt();
                V[i]=sc.nextInt();
            }
 
            //第一行都爲0,java裏省去初始化
           for(int i=1;i<=N;i++){
               for(int j=0;j<=C;j++){
                   if(j-P[i]>=0){
                       dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-P[i]]+V[i]);
                   }else{
                       dp[i][j]=dp[i-1][j];
                   }
               }
           }
            System.out.println(dp[N][C]);
        
        }
         
    }
}

2.在1的基礎上,發現在動態規劃的過程中,永遠是一行和上一行之間的依賴關係。那麼給它分配兩行,循環使用就行了。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext()){
            int C=sc.nextInt();
            int N=sc.nextInt();
            int[] V=new int[N+1];//評價
            int[] P=new int[N+1];//價格
            int[][] dp=new int[2][C+1];//這次只分配兩行給它
 
            for(int i=1;i<=N;i++){
                P[i]=sc.nextInt();
                V[i]=sc.nextInt();
            }
 
            //第一行都爲0,java裏省去初始化
           for(int i=1;i<=N;i++){
               for(int j=0;j<=C;j++){
               		//來回倒騰,不要浪費
                   dp[i%2][j] = dp[(i-1)%2][j];
                   if(j-P[i]>=0){
                       dp[i%2][j]=Math.max(dp[(i-1)%2][j],dp[(i-1)%2][j-P[i]]+V[i]);
                   }else{
                       dp[i%2][j]=dp[(i-1)%2][j];
                   }
               }
           }
            System.out.println(dp[N%2][C]);
        
        }
         
    }
}

3.在2的基礎上,對於一個小單元來說,它永遠只需要自己上方,和自己左方的元素,右邊的不需要。如果把兩行的空間優化成一行。計算當前行,從右往左修改,修改過的值,就是已經固定了的當前行的所求值,還待修改的,就是上一行的遺留值(供後面的使用),當前行和上一行在一行裏同時體現,而且互相不影響,修改的過程中,上一行逐漸變成這一行。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext()){
            int C=sc.nextInt();
            int N=sc.nextInt();
            int[] V=new int[N+1];//評價
            int[] P=new int[N+1];//價格
            int[] dp=new int[C+1];//一行的話,直接一維數組
 
            for(int i=1;i<=N;i++){
                P[i]=sc.nextInt();
                V[i]=sc.nextInt();
            }
 
            //第一行都爲0,java裏省去初始化
            
           for(int i=1;i<=N;i++){
               for(int j=C;j>=0;j--){
                   if(j-P[i]>=0){
                       //注意這裏的細節,左邊的dp[j],表示正在修改的當前行,右邊的dp[j]表示上一行,雖然都是dp[j],但是意義不同
                       dp[j]=Math.max(dp[j],dp[j-P[i]]+V[i]);
                   }
                   /**
                   看不懂的話,加上這句就看懂了
                   else{
                   	 dp[j]=dp[j];
                   }
                   */
               }
           }
            System.out.println(dp[C]);
        
        }
         
    }
}

4.常數級優化1:單純的coding優化。二層for循環的邏輯,這樣寫是一樣的。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext()){
            int C=sc.nextInt();
            int N=sc.nextInt();
            int[] V=new int[N+1];//評價
            int[] P=new int[N+1];//價格
            int[] dp=new int[C+1];//表示dp[i][j]表示前i件放入容量爲j的揹包時的最大評價
 
            for(int i=1;i<=N;i++){
                P[i]=sc.nextInt();
                V[i]=sc.nextInt();
            }

            //第一行都爲0,java裏省去初始化
            
           for(int i=1;i<=N;i++){
               for(int j=C;j>=P[i];j--){
                       dp[j]=Math.max(dp[j],dp[j-P[i]]+V[i]);
               }
           }
            System.out.println(dp[C]);
        }
         
    }
}

5.常數級優化2:揹包九講裏的常數級優化,優化下限公式如圖,但是我感覺會增加計算或者增加空間。沒去實現。
常數優化

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