lc 174. Dungeon Game
https://leetcode.com/problems/dungeon-game/
一个二维矩阵n*m做的地图上,每个都有或正或负的整数,对一从左上到右下的最短路径(每步只能向右或者下)我们走的同时会记录当前位置的累加和s,所以一条路会有n+m-2个位置,所有这些和的最小值是该路径的价值,求价值最大的路。
一个奇怪的dp,这是首先想到的。
因为这个题目让我费解了好一段时间,所以记录思考过程比记录最终解法更有意义。
dp会有一个对于最好状态的记录,这个最好状态记录了之后,其怎么取得的不重要,只有这个值重要,以供后续点使用。(这是一种马尔可夫链的情况,后续状态仅仅由当前决定,却与历史历史无关),由此化指数级别为多项式级别。
但是观察发现这个题目却有两个因素的抗衡,一个是最小值,一个是当前值。有点情况(后面遇到大负数)会希望这个当前值最大化,另一些情况(后面遇到大正数)会希望这个最小值最大化。而继续观察发现,最优解也不必然出现在两个因素的某个最值里,可能某种平衡一点的取值是最优的。dp里面这种情况就要用升维了。对于某个最小值,能取得最大当前值是多少,或者反之。然后本题可以用再次基础上加个优化,就是a的两个因素都差于b,那么a直接被pop出去,可以进一步减少计算量。但是仍然有指数级别的因素参与。
怎么办?强大的二分。。。庞大的数据量在log面前是多么的不堪一击!
二分答案。化优化问题为判断问题。以后我决定了,每次打比赛之前把二分这两个字贴在桌子上。
class Solution: def calculateMinimumHP(self, dungeon): """ :type dungeon: List[List[int]] :rtype: int """ h=len(dungeon) w=len(dungeon[0]) def check(hl): mp=[[None]*w for i in range(h)] mp[0][0]=dungeon[0][0]+hl if mp[0][0]<=0: return False for i in range(1,w): mp[0][i]=None if mp[0][i-1]==None else mp[0][i-1]+dungeon[0][i] if mp[0][i]==None or mp[0][i]<=0: mp[0][i]=None for i in range(1,h): mp[i][0]=None if mp[i-1][0]==None else mp[i-1][0]+dungeon[i][0] if mp[i][0]==None or mp[i][0]<=0: mp[i][0]=None for i in range(1,h): for j in range(1,w): u=mp[i-1][j] l=mp[i][j-1] c=dungeon[i][j] if u==None and l==None: mp[i][j]=None elif u==None: mp[i][j]=l+c if l+c>0 else None elif l==None: mp[i][j] = u + c if u + c > 0 else None else: mp[i][j] = max(l,u)+c if mp[i][j]<=0: mp[i][j]=None if mp[-1][-1]!=None: return True return False upper=10 for i in range(h): for j in range(w): if dungeon[i][j]<0: upper-=dungeon[i][j] if check(1): return 1 l,r=1,upper while r-l>1: m=(r+l)//2 if check(m): r=m else: l=m return r