Recursive dynamic programming ---- violent turn with minimal problems and matrix expansion path

Violence recursive
sub-problems similar problems 1, the problem into the downsizing of the
2, there is a clear need not proceed with the termination condition recursive
3, when there has been a result of the decision making process after the sub-problem
4, you do not need to record each solving a problem child

Dynamic programming
1, from violent recursion
2, the recording solution down each sub-problem, avoid double counting (which is the essential cause better dynamic programming recursion)
3, the recursive process of violence, the state has become abstract expression
4 and there is a simplified expression of the state, may make it more concise

Example topics:

Give you a two-dimensional array, each two-dimensional array of numbers are positive, go to the lower right corner from the top left corner of requirements, each step can only be to the right or down. Digital tired along the way through to
add up. And a minimum return path.

For example,
1, 3, 0
2, 5, 1
7, 4, 2
it is clear and the minimum path = 1 + 0 + 1 + 3 + 2 = 7

1 idea:

This question is the classic dynamic programming method. Here first give a recursive method (try version), is relatively easy to think and understand, the idea: start from the top left corner, is nothing more than one of the following conditions in the process of walking:

1. The current position is a position where the first element, at this time there are only two choices, either go down or go to the right, then the question becomes the current element value + (lower right corner of the path walked down elements and, the right elements in the lower right corner and walked the path whichever is less).

2. The current location right in the last row, this time only option is to go to the right;

3. Current position just in the last one, at this time only one option is to go down;

4. The current location of the element is just the bottom right position, and at this time the entire path plus the current element value.

Code is implemented as follows:

package com.gxu.dawnlab_algorithm8;

/**
 * 矩阵最小路径和问题
 * 
 * @author junbin
 *
 *         2019年7月12日
 */
public class MinPath {
	public static int minPath1(int[][] matrix) {
		return process1(matrix, 0, 0);
	}

	public static int process1(int[][] matrix, int i, int j) {
		if (i == matrix.length - 1 && j == matrix[0].length - 1) { //最后一个元素 
			return matrix[i][j];
		}
		if (i == matrix.length - 1) { //最后一行
			return matrix[i][j] + process1(matrix, i, j + 1);
		}
		if (j == matrix[0].length - 1) { //最后一列
			return matrix[i][j] + process1(matrix, i + 1, j);
		}
		int right = process1(matrix, i, j + 1);
		int down = process1(matrix, i + 1, j);
		return matrix[i][j] + Math.min(right, down); //两种情况,选路径和小的
	}

	// for test
	public static int[][] generateRandomMatrix(int rowSize, int colSize) {
		if (rowSize < 0 || colSize < 0) {
			return null;
		}
		int[][] result = new int[rowSize][colSize];
		for (int i = 0; i != result.length; i++) {
			for (int j = 0; j != result[0].length; j++) {
				result[i][j] = (int) (Math.random() * 10);
			}
		}
		return result;
	}

	public static void main(String[] args) {
		int[][] m = { { 1, 3, 5, 9 }, { 8, 1, 3, 4 }, { 5, 0, 6, 1 },
				{ 8, 8, 4, 0 } };
		System.out.println(minPath1(m));
		// System.out.println(minPath2(m));

		m = generateRandomMatrix(6, 7);
		System.out.println(minPath1(m));
		// System.out.println(minPath2(m));
	}
}

This violence is a recursive process, there is a lot of duplication solution, such as f (0,0) will be taken into account down the f (1,0) and f (0,1) to the right, and f (0,1) and f (1,0) next will take into account (1, 1) in this position f. It can be the f (1,1) to save it recursively repeated use. This is also part of the optimization process is recursive.

Next we will look at how violent turn recursive dynamic programming solver.

Here we must note that not all problems can be changed to violence recursive dynamic programming, it requires two conditions:

(1) there is a lot of violence recursive problem of double counting. As above, the f (1,1) is a double counting.

(2) The problem belongs to "no after-effect" problem. The so-called no aftereffect question refers, no matter what method after arriving at its current location, the current value of the position to which it is to go to the location is fixed, is not affected by the method before. In an example of this question: whether the front reaches the f (1,1) through which path, f (1,1) position to the bottom right of the process does not produce any effect. (Tower of Hanoi belong Markovin problems, because it requires that all the printing process, before making the selection will inevitably affect the subsequent hydrolysis process; N Queens there is also a problem aftereffect)

Then it is clear that this question can be changed to the above dynamic programming.

In the above example procedure :( Example)

  1. How to solve the problem of double counting? The first idea is to record every position to the lower right corner and the minimum path, first of all look at how many variable parameters, how many how many dimension tables you need, here is the variable parameters i and j, so we need a two-dimensional dp table, and matrix-one correspondence, the value dp each position in the table this table is its original two-dimensional table to the bottom right corner of the minimum path and, this time, seeking left to bottom right path and becomes a minimum dp seeking the upper left corner of the table that is the value (0,0) position (note that this is the ultimate goal of our requirements).
  2. Dp values ​​in the table how demand? Then you need to use a recursive function written in front of the violence, first look at the termination condition recursion (base case), the value of the termination condition of position does not rely on the value of other positions, so the value of the lower right corner of the lower right corner of the dp value = matrix :

         matrix --------> dp (x denotes unknown)
         . 1,. 3, 0 --------> X, X, X
         2,. 5,. 1 --------> X , X, X
         . 7,. 4, 2 --------> X, X, 2

     3. Finally, a recursive function can only go down, so the final value dp may be a request, (the last column) = matrix penultimate positions corresponding to the position value position value + dp downwardly, (last column) the reciprocal value of the third position corresponding to the position value = matrix + dp down position:
         Matrix --------> DP (X denotes unknown)
         . 1,. 3, 0 --------> X, X, 0. 1 + 2 +
         2,. 5,. 1 --------> X, X,. 1 + 2
         . 7,. 4, 2 --------> X, X, 2

     4. A recursive function can only go right to the last line, the value of the last line can be obtained for dp, (last line) the penultimate position value = value + dp Matrix position corresponding to the right position, (the last row) Countdown = matrix corresponding to the third position value position value + right position DP:
         Matrix --------> DP (X denotes unknown)
         . 1,. 3, 0 --------> X, X, 0. 1 + 2 +
         2,. 5,. 1 --------> X, X,. 1 + 2
         . 7,. 4, 2 --------> 2,4. 7 + + +. 4 twenty two

     5. Similarly, value = value + dp matrix positions corresponding to the right or down position generally in position dp smaller value
        matrix --------> dp (x denotes unknown)
        1, 3, 0 - -------> X, X, 0. 1 + 2 +
        2,. 5,. 1 --------> X, 5+ (. 1 + 2),. 1 + 2
        . 7,. 4, 2 - -------> 7 + 4 + 2, 4 + 2, 2
       final dp following table:
       7,6,3
       10,8,3
       13,6,2
    value (0, 0) is the position 7 we demand answers.

This is the dynamic programming process can be found recursively turn violent dynamic programming is a fixed routine, as long as you can apply in accordance with the above framework. Of course, the most important step should be to try to write its violence recursive solution, then consider into dynamic programming.

code show as below:

	public static int minPath2(int[][] matrix) {
		if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
			return 0;
		}
		int row = matrix.length;
		int col = matrix[0].length;
		int[][] dp = new int[row][col];
		dp[row-1][col-1] = matrix[row-1][col-1];//右下角的值
		for (int i = row-2; i >= 0; i--) {//最后一列的值
			dp[i][col-1] = dp[i + 1][col-1] + matrix[i][col-1];
		}
		for (int j = col-2; j >= 0; j--) {//最后一行的值
			dp[row-1][j] = dp[row-1][j + 1] + matrix[row-1][j];
		}
		for (int i = row-2; i >= 0; i--) {//普遍位置的值
			for (int j = col-2; j >= 0; j--) {
				dp[i][j] = Math.min(dp[i + 1][j], dp[i][j + 1]) + matrix[i][j];
			}
		}
		return dp[0][0];
	}
	public static void main(String[] args){
		int[][] m = { { 1, 3, 0}, { 2,5,1 }, { 7,4,2 } };
		System.out.println("最小和是:"+minPath1(m));
		System.out.println("最小和是:"+minPath2(m));
	}

 

This article focuses on the blog reference " how to change the dynamic programming recursion violence? "

Published 61 original articles · won praise 9 · views 30000 +

Guess you like

Origin blog.csdn.net/qq_33204444/article/details/95655580