Knapsack Series Problems

Keywords: Java less

I. 01 knapsack problem
Concept: Every item can be taken only once
Solution: See if the last item can go into the backpack
Maximum type problem
n items, known the weight of each item, backpack can bear the weight w, to find the maximum weight can be loaded

 public class Bag010 {
    public static int bag0(int[] arrW,int w) {
        boolean[][] dp = new boolean[arrW.length + 1][w + 1];
        dp[0][0] = true;
        for (int j = 1;j <= w;j++) {
            dp[0][j] = false;
        }
        for (int i = 1;i <= arrW.length;i++) {
            dp[i][0] = true;
            for (int j = 1;j <= w;j++) {
                if (j >= arrW[i - 1]) {
                    dp[i][j] = dp[i - 1] [j] || dp[i - 1][j - arrW[i - 1]];
                }else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        int max = Integer.MIN_VALUE;
        for (int i = w;i >= 0;i--) {
            if (dp[arrW.length][i]) {
                max = i;
                break;
            }
        }

        return max;
    }
}

Given N items, the weights are positive integers A0,A1, A1, respectively. AN-1, values are positive integers V0,V1,... VN-1, a knapsack's maximum load is a positive integer M, which can take away at most what value items (a constraint condition)

public class Bag011 {
    public static void main(String[] args) {
        int[] arrW = {2,3,5,7};
        int[] arrValue = {1,5,2,4};
        int w = 11;
        int maxValue = maxValue1(arrW,arrValue,w);
        System.out.println(maxValue);
    }

    private static int maxValue1(int[] arrW, int[] arrValue, int w) {
        int len = arrW.length;
        int[][] dp = new int[len + 1][w + 1];
        dp[0][0] = 0;
        for (int j = 1;j <= w;j++) {
            dp[0][j] = -1;
        }
        for (int i = 1;i <= len;i++) {
            dp[i][0] = 0;
            for (int j = 1;j <= w;j++) {
                if (j >= arrW[i - 1] && dp[i - 1][j - arrW[i - 1]] != -1) {
                    dp[i][j] = Math.max(dp[i - 1][j],dp[i - 1][j - arrW[i - 1]] + arrValue[i - 1]);
                }else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        int max = Integer.MIN_VALUE;
        for (int j = w;j >= 0;j--) {
            max = dp[len][j] > max ? dp[len][j] : max;
        }
        return max;
    }
    /*Optimized version, because i row only needs i-1 row to calculate the state, using dynamic array instead of a two-dimensional table.
    The constraints are calculated backward and forward (because dp[i - 1][j],dp[i - 1][j - arrW[i - 1]] moves left relative to dp[i][j],
    This allows the calculation to take advantage of pre-update information.*/
    private static int maxValue2(int[] arrW, int[] arrValue, int w) {
        int len = arrW.length;
        int[] dp = new int[w + 1];
        dp[0] = 0;

        for (int i = 1;i <= len;i++) {
            for (int j = w;j >= 0;j--) {
                if (j >= arrW[i - 1] && dp[j - arrW[i - 1]] != -1) {
                    dp[j] = Math.max(dp[j],dp[j - arrW[i - 1]] + arrValue[i - 1]);
                }
            }
        }
        int max = Integer.MIN_VALUE;
        for (int j = w;j >= 0;j--) {
            max = dp[j] > max ? dp[j] : max;
        }
        return max;
    }
}

n items, known the weight and volume of each item, the weight and volume that the backpack can bear, to take away the most valuable items (two constraints)

public class Bag01duowei {
    public static int maxEnergy(int n,int v,int m,int[] arrM,int[] arrV,int[] arrE) {
        if (n <= 0) {
            return 0;
        }
        int[][][] dp = new int[n + 1][m + 1][v + 1];

        for (int i = 0;i <= m;i++) {
            for (int j = 0;j <= v;j++) {
               dp[0][i][j] = -1;
            }
        }
        dp[0][0][0] = 0;
        for (int i = 1;i <= n;i++) {
            for (int j = 0;j <= m;j++) {
                for (int k = 0;k <= v;k++) {
                    if (j >= arrM[i - 1] && k >= arrV[i - 1]
                            && dp[i - 1][j - arrM[i - 1]][k - arrV[i - 1]] != -1) {
                        dp[i][j][k] = Math.max(dp[i - 1][j][k],dp[i - 1][j - arrM[i - 1]][k - arrV[i - 1]] + arrE[i - 1]);
                    }else {
                        dp[i][j][k] = dp[i - 1][j][k];
                    }
                }

            }
        }

        int max = Integer.MIN_VALUE;
        for (int i = m;i >= 0;i--) {
            for (int j = v;j >= 0;j--) {
                max = max < dp[n][i][j] ? dp[n][i][j] : max;
            }
        }
        return max;
    }

    //Optimized procedures
    public static int maxEnergy1(int n,int v,int m,int[] arrM,int[] arrV,int[] arrE) {
        if (n <= 0) {
            return 0;
        }

        int[][] dp = new int[m + 1][v + 1];


        for (int i = 0;i <= m;i++) {
            for (int j = 0;j <= v;j++) {
                dp[i][j] = -1;
            }
        }
        dp[0][0] = 0;
        for (int i = 1;i <= n;i++) {
            for (int j = m;j >= 0;j--) {
                for (int k = v;k >= 0;k--) {
                    if (j >= arrM[i - 1] && k >= arrV[i - 1]
                            && dp[j - arrM[i - 1]][k - arrV[i - 1]] != -1) {
                        dp[j][k] = Math.max(dp[j][k],dp[j - arrM[i - 1]][k - arrV[i - 1]] + arrE[i - 1]);
                    }


                }

            }
        }

        int max = Integer.MIN_VALUE;
        for (int i = m;i >= 0;i--) {
            for (int j = v;j >= 0;j--) {
                max = max < dp[i][j] ? dp[i][j] : max;
            }
        }
        return max;
    }

Ideas for problem solving: Refer to https://blog.csdn.net/qq_36836587/article/details/95889805
Counting Problem
Given N positive integers: A0,A1,... AN-1, a positive integer Target. Find out how many combinations add up to Target, each Ai can only be used once

public class Bag4 {
    public static int ways(int[] arr,int aim) {
        int len = arr.length;
        if (len < 1) {
            return 0;
        }
        int[][] dp = new int[len + 1][aim + 1];
        dp[0][0] = 1;
        for (int j = 1;j <= aim;j++) {
            dp[0][j] = 0;
        }

        for (int i = 1;i <= len;i++) {
            dp[i][0] = 1;
            for (int j = 1;j <= aim;j++) {
                if (j >= arr[i - 1] && dp[i - 1][j - arr[i - 1]] != 0) {
                    dp[i][j] = dp[i - 1][j] + dp[i - 1][j - arr[i - 1]];
                }else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }

        return dp[len][aim];
    }
    //Optimized version
    public static int ways1(int[] arr,int aim) {
        int len = arr.length;
        if (len < 1) {
            return 0;
        }
        int[] dp = new int[aim + 1];
        dp[0] = 1;
        for (int j = 1;j <= aim;j++) {
            dp[j] = 0;
        }

        for (int i = 1;i <= arr.length;i++) {
            dp[0] = 1;
            for (int j = aim;j >= 0;j--) {
                if (j >= arr[i - 1] && dp[j - arr[i - 1]] != 0) {
                    dp[j] = dp[j] + dp[j - arr[i - 1]];
                }
            }
        }

        return dp[aim];
    }

    public static void main(String[] args) {
        int[] arr = {1,2,3,3,7};
        int n = ways1(arr,7);
        System.out.println(n);
    }
}

2. Full Backpack
Concept: Every item can be taken countless times
Look at the weight of the last item to get those.
Counting Problem
f(aim) = f(aim - A0) + f(aim - A1)... + f(aim-AN-1) is not all Ai, only if the condition Ai <= aim is satisfied is added.

public class Bag5 {
    public static int ways(int[] arr,int aim) {
        int len = arr.length;
        if (len < 1) {
            return 0;
        }
        int[] dp = new int[aim + 1];
        dp[0] = 1;
        for (int i = 1;i <= aim;i++) {
            for(int j = 0;j < len;j++) {
                if (i >= arr[j]) {
                    dp[i] += dp[i - arr[j]];
                }
            }
        }
        return dp[aim];
    }

    public static void main(String[] args) {
        int[] arr = {1,2,4};
        int n = ways(arr,4);
        System.out.println(n);
    }
}

Maximum type problem
Given N items, the weights are positive integers A0,A1, A1, respectively. AN-1, values are positive integers V0,V1,... VN-1. Each item has infinite number. The maximum load-bearing capacity of a backpack is the maximum value that a positive integer M can take away.

public class Bag6 {
    public static int maxVal(int[] w,int[] value,int W) {
        int max = 0;
        int len = w.length;
        if (len < 1) {
            return 0;
        }
        int[] dp = new int[W + 1];
        dp[0] = 0;
        for (int i = 1;i <= W;i++) {
            int max1 = 0;
            for (int j = 0;j < len;j++) {
                if (i >= w[j]) {
                    max1 = Math.max(max1,dp[i - w[j]] + value[j]);
                }
            }
            dp[i] = max1;
            max = dp[i] > max ? dp[i] : max;
        }
        return max;
    }

    public static void main(String[] args) {
        int[] w = {2,3,5,7};
        int[] value = {1,5,2,4};
        int W = 10;
        int max = maxVal(w,value,W);
        System.out.println(max);
    }
}

There are many notes with different denominations in RMB. In this question, only seven kinds of notes with different denominations are considered. They are: 1 yuan, 2 yuan, 5 yuan, respectively.
10 yuan, 20 yuan, 50 yuan, 100 yuan. Do you know how many notes are needed to make up the minimum amount of n yuan?
The first group of data is 3, the answer is: 1 yuan + 1 2 yuan, a total of 2 notes. A note.
The second group of data is 4, the answer is: 2 pieces of 2 yuan, a total of 2 pieces of paper money.
The third group of data is 5, the answer is: 1 piece of 5 yuan, a total of 1 note.
The fourth group of data is 9, the answer is: 2 pieces of 2 yuan + 1 piece of 5 yuan, a total of 3 notes. A note.
The fifth group of data is 99. The answer is: 2 sheets of 2 yuan + 1 sheet of 5 yuan + 2 sheets of 20 yuan + 1 sheet of 50 yuan, a total of 6 sheets.

public class Bag3 {

    private static int changeMoney(int[] money, int aim) {
        int len = money.length;
        int[] dp = new int[aim + 1];
        dp[0] = 0;
        for (int i = 1;i <= aim;i++) {
            int min = aim + 1;
            for (int j = 0;j < len;j++) {
                if(i >= money[j]) {
                    min = Math.min(min,dp[i - money[j]] + 1);
                }
            }
            dp[i] = min;

        }
        return dp[aim] == aim + 1 ? -1 : dp[aim];
    }
    //Violent recursive time passes through aim = 99
    private static int changeMoney1(int[] money, int aim) {
        if (aim == 0) {
            return 0;
        }
        int min = aim + 1;
        for (int i = 0;i < money.length;i++) {
            if (aim >= money[i]) {
                min = Math.min(min,changeMoney1(money,aim - money[i]) + 1);
            }

        }
        return min == aim + 1 ? -1 : min;
    }

    public static void main(String[] args) {
        int[] money = {1,2,5,10,20,50,100};
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int aim = Integer.valueOf(sc.nextLine());
            int less = changeMoney(money,aim);
            System.out.println(less);
        }
    }

}

3. Multiple Backpack
There is a limit to the number of items per item.
Consider the number of last items

There are N items and a backpack with a capacity of V.
There are at most si items in the first category. The volume of each item is vi and the value is wi.
To find out which items will be loaded into the backpack, the total volume of the items can not exceed the backpack volume, and the total value is the largest.
Output maximizes value.

import java.util.Scanner;
//Consider the number of last items

public class Main {
    public static int maxVal(int n,int V,int[] arrV,int[] arrNum,int[] arrVaule) {
        int max = 0;
        int[] dp = new int[V + 1];
        dp[0] = 0;
        for (int i = 1;i <= V;i++) {
            dp[i] = -1;
        }
        for (int i = 1;i <= n;i++) {
            for (int j = V;j >= 0;j--) {
                int max1 = 0;
                for (int k = 0;k <= arrNum[i - 1] && k * arrV[ i - 1] <= j;k++) {
                    max1 = Math.max(max1,dp[j - arrV[ i - 1] * k] + k * arrVaule[i - 1]);
                }
                dp[j] = max1;
            }

        }
        for (int i = V;i >= 0;i--) {
            max = dp[i] > max ? dp[i] : max;
        }
       return max;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        while (sc.hasNext()) {
            String[] strs = sc.nextLine().split(" ");
            int n = Integer.valueOf(strs[0]);
            int V = Integer.valueOf(strs[1]);
            int[] arrV = new int[n];
            int[] arrVal = new int[n];
            int[] arrNum = new int[n];
            for (int i = 0;i < n;i++) {
                String[] strs1 = sc.nextLine().split(" ");
                arrV[i] = Integer.valueOf(strs1[0]);
                arrVal[i] = Integer.valueOf(strs1[1]);
                arrNum[i] = Integer.valueOf(strs1[2]);
            }
            int max = maxVal(n,V,arrV,arrNum,arrVal);
            System.out.println(max);
        }
    }
}

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

//Converting to the 01 knapsack problem, the time complexity changes from n*w*s to n*w*logs
public class Bag8 {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        while (sc.hasNext()) {
            String[] strs = sc.nextLine().split(" ");
            int n = Integer.valueOf(strs[0]);
            int V = Integer.valueOf(strs[1]);
            int[] arrV = new int[n];
            int[] arrVal = new int[n];
            int[] arrNum = new int[n];
            for (int i = 0;i < n;i++) {
                String[] strs1 = sc.nextLine().split(" ");
                arrV[i] = Integer.valueOf(strs1[0]);
                arrVal[i] = Integer.valueOf(strs1[1]);
                arrNum[i] = Integer.valueOf(strs1[2]);
            }

            List<Integer> listVal = new ArrayList<>();
            List<Integer> listV = new ArrayList<>();
            for (int i = 0; i < n;i++) {
                int s = arrNum[i];
                for (int k = 1; k <= s;k *= 2) {
                    s -= k;
                    listVal.add(k*arrVal[i]);
                    listV.add(k*arrV[i]);
                }
                if (s > 0) {
                    listVal.add(s*arrVal[i]);
                    listV.add(s*arrV[i]);
                }
            }
            int n1 = listV.size();
            int val = maxVal(n1,V,listV,listVal);
            System.out.println(val);
        }
    }

    private static int maxVal(int n, int v, List<Integer> listV, List<Integer> listVal) {
        if (n < 1) {
            return 0;
        }
        int[] dp = new int[v + 1];
        dp[0] = 0;
        for (int j = 1;j <= v;j++) {
            dp[j] = -1;
        }
        for (int i = 1;i <= n;i++) {
            for (int j = v;j >= 0;j--) {
                if (j >= listV.get(i - 1) && dp[j - listV.get(i - 1)] != -1) {
                    dp[j] = Math.max(dp[j],dp[j - listV.get(i - 1)] + listVal.get(i - 1));
                }
            }
        }
        int max = 0;
        for (int j = v;j >= 0;j--) {
            max = dp[j] > max ? dp[j] : max;
        }
        return max;
    }

}

4. Mixed Backpack
01 backpack, multiple backpack, full backpack
Convert the multiple knapsack to 01 knapsack, then judge the two types and answer in different ways.

There are N items and a backpack with a capacity of V.
There are three types of articles:
Category I items can only be used once (01 knapsack);
The second category of items can be used infinitely (full backpack);
The third category of items can only be used si times at most (multiple backpacks);
Each volume is vi and the value is wi.
To find out which items will be loaded into the backpack, the total volume of the items can not exceed the backpack volume, and the total value is the largest.
Output maximizes value.

public class Bag9 {
    public static class Node {
        public int kind;
        public int v;
        public int val;

        public Node(int kind1,int v1,int val1) {
            this.kind = kind1;
            this.v = v1;
            this.val = val1;
        }
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            List<Node> list = new ArrayList<>();
            String[] strs = sc.nextLine().split(" ");
            int N = Integer.valueOf(strs[0]);
            int V = Integer.valueOf(strs[1]);
            for (int i = 0;i < N;i++) {
                String[] strs1 = sc.nextLine().split(" ");
                int v = Integer.valueOf(strs1[0]);
                int val = Integer.valueOf(strs1[1]);
                int s = Integer.valueOf(strs1[2]);
                if (s == -1) {
                    list.add(new Node(-1,v,val));
                }else if (s == 0) {
                    list.add(new Node(0,v,val));
                }else {
                    for (int k = 1;k <= s;k *= 2) {
                        s -= k;
                        list.add(new Node(-1,k*v,k*val));
                    }
                    if (s > 0) {
                        list.add(new Node(-1,s*v,s*val));
                    }
                }
            }
            int max = maxVal(N,V,list);
            System.out.println(max);
        }
    }

    private static int maxVal(int n, int v, List<Node> list) {
        if (n < 1) {
            return 0;
        }
        int[] dp = new int[v + 1];
        dp[0] = 0;
        for (int j = 1;j <= v;j++) {
            dp[j] = -1;
        }
        for (Node node : list) {
            if (node.kind == -1) {
                for (int j = v;j >= 0;j--) {
                    if (j >= node.v && dp[j - node.v] != -1) {
                        dp[j] = Math.max(dp[j],dp[j - node.v] + node.val);
                    }
                }
            }else {
                for (int j = 1;j <= v;j++) {
                    if (j >= node.v && dp[j - node.v] != -1) {
                        dp[j] = Math.max(dp[j],dp[j - node.v] + node.val);
                    }
                }
            }
        }
        int max = 0;
        for (int j = v;j >= 0;j--) {
            max = dp[j] > max ? dp[j] : max;
        }
        return max;
    }
}

Group Backpack
Consider Max (the last set of items is not packed, which one is the last set of items). Multiple backpacks are special packaged backpacks.

There are N items and a backpack with a capacity of V.
There are several items in each group, and only one item in the same group can be selected at most.
The volume of each item is vij, the value is wij, where i is the group number and j is the group number.
To find out which items will be loaded into the backpack, the total volume of the items will not exceed the backpack volume, and the total value will be the largest.
Output maximizes value.

import java.util.Scanner;

public class Bag10 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String[] strs = sc.nextLine().split(" ");
            int N = Integer.valueOf(strs[0]);
            int V = Integer.parseInt(strs[1]);

            int[] dp = new int[V + 1];
            dp[0] = 0;
            for (int j = 1;j < N;j++) {
                dp[j] = -1;
            }

            for (int i = 0;i < N;i++) {
                int s = Integer.valueOf(sc.nextLine().split(" ")[0]);
                int[] arrV = new int[s];
                int[] arrVal = new int[s];
                for (int j = 0;j < s;j++) {
                    String[] strs1 = sc.nextLine().split(" ");
                    arrV[j] = Integer.valueOf(strs1[0]);
                    arrVal[j] = Integer.valueOf(strs1[1]);
                }
                for (int j = V;j >= 0;j--) {
                    for (int k = 0;k < s;k++) {
                        if (j >= arrV[k] && dp[j - arrV[k]] != -1) {
                            dp[j] = Math.max(dp[j],dp[j - arrV[k]] + arrVal[k]);
                        }
                    }
                }

            }
            int max = 0;
            for (int j = V;j >= 0;j--) {
                max = dp[j] > max ? dp[j] : max;
            }
            System.out.println(max);
        }
    }
}

summary
Type of knapsack
01 knapsack is a two-dimensional dp, which can be optimized by rolling array; complete knapsack itself is a one-dimensional dp, which does not need to be optimized by rolling array; multiple knapsack is a two-dimensional dp, which can be optimized by rolling array, and can be converted into 01 knapsack to optimize time (when writing code in java). To convert a list into a 01 knapsack, because the array must be initialized; a mixed knapsack can only be written as an optimized one-dimensional dp, because the full knapsack itself is a one-dimensional dp, in addition, two traversals of the full knapsack code need to be exchanged for positions; the packet knapsack begins to solve problems when reading the data is relatively simple and does not need to. Save all the data first, and then begin to solve the problem; in fact, all knapsack problems can start to solve the problem in the time of reading the data, which is relatively simple, but also save space. All the above mentioned cases have only one constraint condition, and the two-dimensional or multi-dimensional solutions are the same.
Return results
In addition to the above counting type, the most value type, sometimes will let you collect solutions, this time do not use the optimized version, because need to use two different states of i to compare, see if you want an item, collect it.
for example
There are N items and a backpack with a capacity of V. Each item can only be used once.
The volume of item i is vi and the value is wi.
To find out which items will be loaded into the backpack, the total volume of these items can not exceed the backpack volume, and the total value is the largest.
Output dictionary order minimization scheme. The dictionary order here refers to the sequence formed by the number of the selected item. Item number range is 1. N.

import java.util.Scanner;

public class Bag12 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        while (sc.hasNext()) {
            String[] strs = sc.nextLine().split(" ");
            int N = Integer.valueOf(strs[0]);
            int V = Integer.valueOf(strs[1]);
            int[][] dp = new int[N + 1][V + 1];

            int[] arrV = new int[N];
            int[] arrVal = new int[N];
            for (int i = 0;i < N;i++) {
                String[] strs1 = sc.nextLine().split(" ");
                int v = Integer.valueOf(strs1[0]);
                int val = Integer.valueOf(strs1[1]);
                arrV[i] = v;
                arrVal[i] = val;
            }
            //It means to choose from the back to the front, dp[N][0] means none, and dp[N - 1][v] means the penultimate one to pack the backpack v.
            dp[N][0] = 0;
            for (int j = 1;j <= V;j++) {
                dp[N][j] = -1;
            }
            //It means to choose from the back to the front.
            for (int i = N - 1;i >= 0;i--) {
                for (int j = 0;j <= V;j++) {
                    if (j >= arrV[i] && dp[i + 1][j - arrV[i]] != -1) {
                        dp[i][j] = Math.max(dp[i + 1][j],dp[i + 1][j - arrV[i]] + arrVal[i]);
                    }else {
                        dp[i][j] = dp[i + 1][j];
                    }
                }
            }
            int s = 0;
            int max = 0;
            for (int j = V;j >= 0;j--) {
                if (dp[0][j] > max) {
                    max = dp[0][j];
                    s = j;
                }
            }
            //From going to the back-election, there must be one that can be chosen.
            for (int i = 0;i < N;i++) {
                if (s >= arrV[i] && dp[i][s] == dp[i + 1][s - arrV[i]] + arrVal[i]) {
                    System.out.print(i + 1 + " ");
                    s -= arrV[i];
                }
            }
            System.out.println();


        }
    }

}

Posted by weevil on Tue, 20 Aug 2019 02:12:11 -0700