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

 

posted @ 2019-04-11 14:23  Cloud.9  阅读(147)  评论(0编辑  收藏  举报