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
solved
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
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
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",
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
we are required to shift the third line above,
so we can merge the second and third line expressions And get the following result
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
then we shift the term a [0] [n-2] in the second line of expression, to get
easy
to get the minimum requirement, take the equal sign, get
For this formula, we generalize to the general conclusion of this shape dungeon
Similarly, for the dungeon of {mx 1} (m rows and 1 column), we can draw a similar conclusion. In
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.
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).
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
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
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,
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
to (2). Similarly, there is
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
when i = m-1 and
j = n-1 in
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]