Dynamic programming - 01 knapsack problem

Problem description : Given N items and a knapsack of capacity C, item i has weight wi and value vi.

Q : How should the items to be loaded into the backpack be selected so that the total value of the items loaded into the backpack is maximized?

Topic analysis : Select m items from N items and put them into a backpack with a capacity of C, v1+v2+v3+...+vm is the largest, that is, to find the optimal solution, here we use dynamic programming to solve this problem. The problem needs to solve the optimal solution when the capacity of the backpack is C, then we can decompose the problem, increase the capacity of the backpack from 1 to C, and solve the optimal solution when the capacity is 1 and the optimal solution when the capacity is 2 in turn; then based on The nature of dynamic programming to find the optimal solution - after the optimal solution of the sub-problems is aggregated, the optimal solution of the total problem is obtained, and we can obtain the optimal solution of the knapsack problem.

Dynamic programming : Similar to the divide and conquer method, dynamic programming divides a big problem into small problems, and solves each small problem by finding the recursive relationship between the big problem and the small problem, and finally achieves the effect of solving the original problem. But the difference is that the divide-and-conquer method has been repeatedly calculated many times on sub-problems and sub-sub-problems, while dynamic programming has memory, and records all solved sub-problems answers by filling in the form. The sub-problems used can be directly extracted, which avoids repeated calculations and saves time. Therefore, after the problem meets the optimality principle, the core of solving the problem with dynamic programming is to fill in the form. After the form is filled in, the optimal solution will be turn up.

Implementation idea: declare an array table[N+1][C+1], table[i][j] represents the maximum value of the product that can be obtained when the knapsack capacity is j and the i-th product is selected. Now we need to implement a function initTable(int[] value, int[] weight, int N, int capacity), which is used to initialize this table, and the value[i] array represents the value of the ith commodity (i starts from 1 Calculation), weight[i] represents the weight of the i-th commodity, that is, the capacity of the knapsack.

In the face of a commodity, we have two options: loading the backpack and not loading the backpack, then let's analyze the calculation method of table[i][j].

(1) In the case of j < w[i], at this time, the capacity of the backpack is not enough to put down the i-th item, so you can only choose not to take it: m[ i ][ j ] = m[ i-1 ][ j ]

(2) In the case of j >= w[i], then the knapsack capacity can hold the i-th item, and we have to consider whether taking this item can obtain greater value.

        拿:table[i ][j]  = table[ i-1 ][ j - weight[i] ] + value[ i ]

        不拿:table[i ][j] = table[ i - 1 ][ j ]

We need to compare the values ​​of table[i ][j] in both cases and choose accordingly.

Now we write out the implementation code:

/**
	 * Initialize the table, the value in the lower right corner of the table is the optimal solution
	 * @param value value array
	 * @param weight weight array
	 * @param N product type
	 * @param capacity backpack capacity
	 * @return table
	 */
	private static int[][] initTable(int[] value, int[] weight, int N, int capacity) {
		if(value.length != weight.length) {
			System.out.println("The parameter value and weight are wrong");
			return null;
		}
		int[][] table = new int[N + 1][capacity + 1];
		for(int i = 1; i <= N; i++) {
			for(int j = 1; j <= capacity; j++) {
				if(j < weight[i]) {//Can't fit
					table[i][j] = table[i-1][j];
				} else {//Can be installed
					if(table[i-1][j] > (table[i-1][j-weight[i]] + value[i])) {//不装i价值更大
						table[i][j] = table[i-1][j];
					} else {//The value of i is bigger
						table[i][j] = table[i-1][j-weight[i]] + value[i];
					}
				}
			}
		}
		
		return table;
	}

In this way, the optimal solution can be obtained, and the optimal solution is table[N] [ capacity ] . However, we also want to obtain which kinds of commodities have been selected, and how can this be achieved? Here we know the optimal solution, then we can use reverse thinking to think about it, the optimal solution is table[ i ] [ j ], then table[ i ] [ j ] = table[ i -1 ] [ j ] or table [ i - 1 ] [ j - weight [i] ] + value[i] , we can solve it according to the idea of ​​initializing the table:

             1) When table[ i ][ j ] = table[ i -1 ] [ j ], it means that the i-th product is not selected, then return to V(i-1,j);

             2) When table[ i ][ j ] = table[ i - 1 ] [ j - weight [i] ] + value[i] , it means that the i-th product is loaded, which is part of the optimal solution, and then We have to go back to V(i-1,jw(i)) before loading the item;

       3)  Traverse until the end of i < 0, all solutions will be found.

code show as below:

	/**
	 * Obtain the selected product through backtracking: backtracking to find the composition of the solution based on the optimal solution
	 * @for me
	 * @param j
	 * @param table information record table
	 * @param weight weight array
	 * @param value value array
	 * @param result returns the result array
	 */
	private static void findChoice(int i, int j, int[][] table, int[] weight, int[] value, int[] result) {
		if(i > 0) {
			if(table[i][j] == table[i-1][j]) {//The i-th product is not selected
				result[i] = 0;
				findChoice(i-1, j, table, weight, value, result);
			} else if(table[i][j] == (table[i-1][j-weight[i]] + value[i])) {//The i-th item is selected
				result[i] = 1;
				findChoice(i-1, j-weight[i], table, weight, value, result);
			}
		}
	}

The main function test is as follows:

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int N = 0;
		int capacity;
		int[] value;
		int[] weight;
		//Initialization data
		//Input format: 4 8//Enter product type (N) and backpack capacity (capacity)
		// 2 3 4 5//Enter the weight of each type of commodity (the value that occupies the capacity of the backpack)
		// 3 4 5 6//Enter the value of each item
		N = sc.nextInt();
		capacity = sc.nextInt();
		if(N <= 0) {
			System.out.println("The input parameter N is wrong");
			return;
		}
		value = new int[N+1];
		weight = new int[N+1];
		for(int i = 1; i <= N; i++) {//Initialize the weight array
			weight[i] = sc.nextInt();
		}
		for(int i = 1; i <= N; i++) {//initialize the value array
			value[i] = sc.nextInt();
		}
		
		
		int[][] table = initTable(value, weight, N, capacity);
		System.out.println("最优解:" + table[N][capacity]);
		int[] choice = new int[N+1];
		findChoice(N, capacity, table, weight, value, choice);
		System.out.println("Select the product array, 1 means choice, 0 means no choice: " + Arrays.toString(choice));
		sc.close();
	}


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325652219&siteId=291194637