Leetcode brushing record-174. Dungeon game (thoughts have been added, with strict mathematical derivation)

Insert picture description here
This question is difficult, not difficult to think of to do with the idea of ​​dynamic programming,
but rather how to consider sub-problems, processing order and state transition equations.

We first rephrase the requirements of the topic as
"At any moment, the knight's health value x is greater than or equal to 1"

Next, we define according to the requirements of the title, assuming the size of the dungeon is {mxn}
**

The meaning of DP [i] [j] is to make the knight go from i, j to the lower right corner during the entire process. The initial blood volume is not less than 1, and finally DP [0] [0] can be obtained.

**

So is it from top left to bottom right, or bottom right to top left?
Let ’s decide first.
Let ’s assume that the knight ’s initial life value is x, and use a to represent the two-dimensional matrix of the dungeon.

According to the experience of the usual dynamic planning of two-dimensional array movement,
we will simplify the problem first and divide it into the following three cases

1. If the size of the dungeon is {1x1} (only 1 grid)
At this time, we do not need to consider the direction of the sub-problem solution. The
knight only needs to enter the unique room and keep it after the health value interacts with the house The blood volume of at least 1
is
Insert picture description here
solved
Insert picture description here

Since we need to obtain the lowest possible value of the initial life, we can directly take the equal sign in front of max

2. If the size of the dungeon is {1 xn} or {mx 1}
At this time, we need to consider the direction in which the subproblem is solved!

We have a {1 xn} (1 rows and n columns) as an example of the dungeon
this is a dungeon
a = [[a[0][0],a[0][1],...,a[0][n-1]]

Suppose we upper left (a [0] [0] ) to the lower right (a [0] [n- 1])
through the first grid, similar to the above "1,"
there
Insert picture description here
but this time, if you do not know a [0] [1] ~ a [0] [n-1] The value
of dp [0] [0] ca n’t be derived because we do n’t know the next grid, so we ca n’t determine the initial health value.

Therefore, we must consider evolution from the lower right to the upper left!

Therefore, we first consider that if we start from the last grid a [0] [n-1], since it also triggers a life value interaction
, similar to "1",
Insert picture description here
we move the starting point to the left a [0] [n -2]
If we start from a [0] [n-2] with the health value x, then
Insert picture description here
we are required to shift the third line above,
Insert picture description here
so we can merge the second and third line expressions And get the following result
Insert picture description here

At this time, we miraculously found that the formula on the right after the merger is not DP [0] [n-1]? ?
Therefore, we substitute DP [0] [n-1] to get, and
Insert picture description here
then we shift the term a [0] [n-2] in the second line of expression, to get
Insert picture description here
easy
Insert picture description here
to get the minimum requirement, take the equal sign, get
Insert picture description here
For this formula, we generalize to the general conclusion of this shape dungeon
Insert picture description here

Similarly, for the dungeon of {mx 1} (m rows and 1 column), we can draw a similar conclusion. In
Insert picture description here
this way, we solved the situation of one row with multiple columns, or one column with multiple rows

3. In general, that is {mxn} (the dungeon has m rows and n columns, both of which are> 1).
As we have already concluded in "2,":
On the premise that you can only choose to move right or down, a
single row Or a single column of dungeons, the DP value of each grid is only related to this row or column

Even if there are m rows and n columns,
if we start from the last row, then we have only one route, that is, going all the way to the right (it has nothing to do with the value of a in other rows),
if we send from the last column, then we have only one route, namely All the way down (it has nothing to do with the value of a in other columns),
so we initialize the bottom two rows and the rightmost one of the m rows and n columns according to the last two formulas in "2,"

In other words, to fill the DP matrix,
we can initialize the gray part in the figure below according to the conclusion obtained above.
Insert picture description here
Next, we start filling from a [m-2] [n-2], and we can fill the m-th first. 2 rows, you can also fill the n-2 column
first. Let's fill in the m-2 behavior first, as shown below (hereafter, we use green to indicate the initialized grid).
Insert picture description here
Based on experience in dealing with this type of problem, we will sub-problem Locked in a local 2x2 grid.
In the order of the above figure, we can ensure that the DP values ​​below the grid i, j, the right side, and the lower right of the DP value to be calculated are known every time
. As shown in
Insert picture description here
the following figure From i, j to i + 1, j + 1, we have only two choices, namely
(1) i, j-move down-> i + 1, j-move right-> i + 1, j + 1
(2) i, j-right shift-> i, j + 1-down shift-> i + 1, j + 1
If (1),
suppose the initial life is x, there
Insert picture description here
is its The meaning is that the initial life is not less than 1, and the minimum required value after i, j is not less than 1 and not less than i + 1, j

Therefore,
Insert picture description here
considering the above recursive formula, we can ensure that the DPs that have been obtained are not less than 1 (it can also be understood that the initial blood volume must be not less than 1)
. The above formula can be simplified
Insert picture description here
to (2). Similarly, there is
Insert picture description here

Next is the key, because there are two roads to go, we want to find the minimum required value,
so as long as there is one that meets the life value is greater than or equal to 1, therefore, we take the above two inequalities OR,
that is, let x is greater than or equal to the smaller of the two max

That is, when 0 ≤ i ≤ m-2 and 0 ≤ j ≤ n-2
Insert picture description here
when i = m-1 and
Insert picture description here
j = n-1 in
Insert picture description here
this way, we get the state transition equation of dynamic programming

class Solution:
    def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:
        m = len(dungeon)
        n = len(dungeon[0])
        if m == 1 and n == 1:#1x1的地牢
            return max(1,1-dungeon[0][0])
        elif m == 1 and n != 1:#1xn的地牢
            newlist = []
            for i in range(n):
                newlist.append(-1)
            newlist[-1] = max(1,1-dungeon[0][-1])
            for i in range(n-1):
                tempindex = n - i - 2
                newlist[tempindex] = max(1,newlist[tempindex+1] - dungeon[0][tempindex])
            return newlist[0]
        elif m != 1 and n == 1:#nx1的地牢
            newlist = []
            for i in range(m):
                newlist.append(-1)
            newlist[-1] = max(1,1-dungeon[-1][0])
            for i in range(m-1):
                tempindex = m - i - 2
                newlist[tempindex] = max(1,newlist[tempindex+1] - dungeon[tempindex][0])
            return newlist[0]
        #以下针对mxn的地牢,m和n都大于1
        #初始化一个m行n列的dplist
        print('地牢的size为',m,n)
        newlist = []
        for i in range(m):
            templist = []
            for j in range(n):
                templist.append(-1)            
            newlist.append(templist)
        #我们先初始化最下面一行和最右边一列
        #先初始化最右下角的
        newlist[m-1][n-1] = max(1,1 - dungeon[-1][-1])
        tempinit = newlist[-1][-1]
        #最下面一行,共n-1个待补充的数字
        for i in range(n-1):
            tempindex = n - i - 2
            newlist[-1][tempindex] = max(1,newlist[-1][tempindex+1] - dungeon[-1][tempindex])
        #最右边一列,共m-1个待补充的数字
        for j in range(m-1):
            tempindex = m - j - 2
            newlist[tempindex][-1] = max(1,newlist[tempindex+1][-1] - dungeon[tempindex][-1])
        #从[m-2][n-2]开始填充,一直到[0][0],共(m-1)x(n-1)个
        #先从倒数第二行倒数第二列开始,然后是倒数第二行倒数第三列,......
        for i in range(m-1):
            tempi = m - i - 2
            for j in range(n-1):
                tempj = n - j - 2
                newlist[tempi][tempj] = max(1,min(newlist[tempi+1][tempj],newlist[tempi][tempj+1])-dungeon[tempi][tempj])
        print(newlist)
        return newlist[0][0]


Published 43 original articles · praised 14 · 20,000+ views

Guess you like

Origin blog.csdn.net/weixin_41545780/article/details/105132516