Rookie brush question (14) [01 knapsack question]

Posted by xgrewellx on Mon, 31 Jan 2022 11:56:13 +0100

[01 knapsack problem]

There are # N items and a backpack with a capacity of # V. Each item can only be used once.

The volume of the # i # article is # vi and the value is # wi.

Solve which items are loaded into the backpack, so that the total volume of these items does not exceed the backpack capacity, and the total value is the largest.
Output maximum value.

Input format

In the first line, two integers, N and V, are separated by spaces, representing the number of items and the volume of the backpack respectively.

Next, there are ^ N ^ lines, with two integers ^ vi,wi,, separated by spaces, representing the volume and value of the ^ ii article respectively.

Output format

Output an integer representing the maximum value.

Data range

0<N,V≤10000<N,V≤1000
0<vi,wi≤1000

Code (2D array version):

private static void Bag_01(){
        int N=1010;
        Scanner in =new Scanner(System.in);
        int n,m;//n number of items, m backpack volume
        n=in.nextInt();
        m=in.nextInt();
        int[] v=new int[n+1];//Item array
        int[] w=new int[n+1];//Item value array
        int[][] dp=new int[N][N];//Total value
        for(int i=1;i<=n;i++){
            v[i]=in.nextInt();
            w[i]=in.nextInt();
        }
        for(int i=1;i<=n;i++){
            for(int j=0;j<=m;j++){
                dp[i][j]=dp[i-1][j];
                if(j>=v[i]){
                    dp[i][j]=Math.max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
                }
            }
            System.out.println("\n");
            System.out.println("The first"+i+"Items");
            for(int k=0;k<n;k++){
                for(int t=0;t<=m;t++){
                    System.out.print(dp[k][t]+" ");
                }
                System.out.println("\n");
            }
        }
        System.out.println(dp[n][m]);
    }

dp[i][j]=Math.max(dp[i][j],dp[i-1][j-v[i]]+w[i]);

analysis:

On the i-th item

Or don't put it in and maintain the value of the first i-1 items

Or put it in, dp[i-1][j-v[i]]+w[i], which is the maximum value of the first i-1 item + the value of the i-th item to be selected, but I can't understand why I traverse j from 0 to the most band and why I write it as j-v[i]. So I summarized my understanding. It will be more clear with two-dimensional array diagram. Video: https://www.bilibili.com/video/BV1XD4y1S7nv?from=search&seid=6022281859510960430

My understanding is: dp[i-1][j-v[i]]+w[i] is to directly take out the first i-1 item and then put it into the i-th item (judged by if, so it must fit after taking out the first i-1 item). After putting it in, dp plus the value of the i-th item, and then calculate the remaining volume = current backpack volume (j) - the volume of the i-th item (v[i]), According to the size of the remaining volume, go forward (two-dimensional array) to find the maximum value of the first i-1 items.

 

Code (one-dimensional array space optimized version):

    private static void Bag_01you(){
        int N=1010;
        Scanner in =new Scanner(System.in);
        int n,m;//n number of items, m backpack volume
        n=in.nextInt();
        m=in.nextInt();
        int[] v=new int[n+1];//Item array
        int[] w=new int[n+1];//Item value array
        int[] dp=new int[N];//Total value
        for(int i=1;i<=n;i++){
            v[i]=in.nextInt();
            w[i]=in.nextInt();
        }
        for(int i=1;i<=n;i++){
//            for(int j=0;j<=m;j++){
//                if(j>=v[i]){
//                    dp[j]=Math.max(dp[j],dp[j-v[i]]+w[i]);
//                }
//            }
            for(int j=m;j>=v[i];j--){
                if(j>=v[i]){
                    dp[j]=Math.max(dp[j],dp[j-v[i]]+w[i]);
                }
            }

            System.out.println("The first"+i+"Items");
            for(int k=0;k<6;k++){
                System.out.print(dp[k]+" ");
            }
            System.out.println("\n");
        }
        System.out.println(dp[m]);
    }

Note that the traversal knapsack size j is in reverse order, which took a long time to understand

We changed dp[i-1][j-v[i]] into dp[j-v[i]]. If it is in order, dp[j-v[i]] is not the maximum value of the first i-1 item, but the current i-th item, which will cause the problem of repetition. Of course, I didn't quite understand this sentence at the beginning, so I used a process to explain it

We assume that the input is:

4 5
1 2
2 4
3 4
4 5

If j is positive ergodic

            for(int j=0;j<=m;j++){
                if(j>=v[i]){
                    dp[j]=Math.max(dp[j],dp[j-v[i]]+w[i]);
                }
            }

When i=1

dp[0]=0 dp[1]=2 dp[2]=max(dp[2],dp[2-1]+2)=4

When you can see dp[2], dp[2-1] is used, that is, dp[1] is dp[1] of current i=1, not dp[1] of i-1. dp[2] is wrong, and the rest is wrong

 

If j is traversal in reverse order

            for(int j=m;j>=v[i];j--){
                if(j>=v[i]){
                    dp[j]=Math.max(dp[j],dp[j-v[i]]+w[i]);
                }
            }

j decrement, j-v[i] decrement, j-v[i] must be the value of the previous i-1 that has not been calculated for the current i-th item

When i=1

dp[5]=max(dp[5],dp[5-1]+2)=2
dp[4]=max(dp[4],dp[4-1]+2)=2
dp[3]=max(dp[3],dp[3-1]+2)=2
dp[2]=max(dp[2],dp[2-1]+2)=2
dp[1]=max(dp[1],dp[1-1]+2)=2

When i=2

dp[5]=max(dp[5],dp[5-2]+4)=max(dp[5],dp[3]+4)=6
dp[4]=max(dp[4],dp[4-2]+4)=max(dp[4],dp[2]+4)=6
dp[3]=max(dp[3],dp[3-2]+4)=max(dp[3],dp[1]+4)=6
dp[2]=max(dp[2],dp[2-2]+4)=max(dp[2],dp[0]+4)=4

Topics: Java Algorithm Dynamic Programming