1. 程式人生 > >LeetCode題解:Dungeon Game——論如何讓王子救出公主

LeetCode題解:Dungeon Game——論如何讓王子救出公主

題目(好久沒看見這麼有趣的了)

The demons had captured the princess § and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.

The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0’s) or contain magic orbs that increase the knight’s health (positive integers).

In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.

Write a function to determine the knight’s minimum initial health so that he is able to rescue the princess.

For example, given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.

在這裡插入圖片描述

Note:

The knight’s health has no upper bound.
Any room can contain threats or power-ups, even the first room the knight enters and the bottom-right room where the princess is imprisoned.

好孩子不要學的反面例子

一開始沒仔細想,還以為就是一平平無奇的字串編輯距離的變體,結果過了幾個樣例就止步了。然後發現騎士在整個過程中都不能死,所以,我們要找的呢,並不是像下面這樣的全域性最優解,而是需要找到這樣一條路徑,使得這條路徑中生命值最小的點是所有可能路徑中的最小值點裡面最大的那一個。這就好像要在幾個村之間修小學,要在所有可能的選點中選擇那個即使是對於相距最遠的村子,裡面的小孩也能承擔得起到達這個點的路上花費的成本。

#include <iostream> 
#include <vector>
using namespace std;
class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
        int m = dungeon.size();
        int n = dungeon[0].size();
        for (int i = 1; i < m; i++) {
        	dungeon[i][0] += dungeon[i-1][0];
        }
        for (int i = 1; i < n; i++) {
        	dungeon[0][i] += dungeon[0][i-1];
        }
        for (int i = 1; i < m; i++) {
        	for (int j = 1; j < n; j++) {
        		dungeon[i][j] += (dungeon[i-1][j] > dungeon[i][j-1] ? dungeon[i-1][j]:dungeon[i][j-1]);
        	}
        }
        return (dungeon[m-1][n-1] > 0 ? 1 : 1 - dungeon[m-1][n-1]);
    }
};

好孩子也不要這樣暴力遍歷哦

#include <iostream> 
#include <vector>
using namespace std;
class Solution {
	//需要找到這樣一條路徑,使得這條路徑中生命值最小的點是所有可能路徑中最大的,而不是最優的解
public:
	int maxnumber = -10000;
	//引數依次是矩陣的大小,當前的橫縱座標,傳入的地牢矩陣,當前生命值,本路徑最小生命值
	void traverse(int m, int n, int curx, int cury, vector<vector<int>>& dungeon, int curnumber, int minnumber) {
		if (curnumber < maxnumber) {
			return;
		}
		minnumber = (minnumber > curnumber ? curnumber : minnumber);
		if (curx == m-1 && cury == n-1) {
			maxnumber = (maxnumber < minnumber ? minnumber : maxnumber);
			return;
		}
		if (cury < n-1) {
			traverse(m, n, curx, cury+1, dungeon, curnumber+dungeon[curx][cury+1], minnumber);
		}
		if (curnumber < maxnumber) {
			return;
		}
		if (curx < m-1) {
			traverse(m, n, curx+1, cury, dungeon, curnumber+dungeon[curx+1][cury], minnumber);
		}
	}
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
        int m = dungeon.size();
        int n = dungeon[0].size();
        //貌似並不需要標記
        //vector<vector <int> > flag(m ,vector<int>(n,0));
        traverse(m, n, 0, 0, dungeon, dungeon[0][0], dungeon[0][0]);
        return (maxnumber > 0 ? 1 : 1 - maxnumber);
    }
};

在這裡插入圖片描述

算了,還是看大佬的動歸解法吧。

其實思路也不是太難,只是要倒著往前推,並且確保每一步裡騎士都還是活著的,果然還是我太笨了。

#include <iostream> 
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
        int m = dungeon.size();
        int n = dungeon[0].size();
        //含義為為了能夠成功到達終點,某點的最少血量
        vector <vector<int>>Flood (m, vector<int>(n, 0));
        Flood[m-1][n-1] = 1;
        for (int i = m-2; i >= 0; i--) {
        	Flood[i][n-1] = max(1, Flood[i+1][n-1]-dungeon[i+1][n-1]);
        }
        for (int i = n-2; i >= 0; i--) {
        	Flood[m-1][i] = max(1, Flood[m-1][i+1]-dungeon[m-1][i+1]);
        }
        for (int i = m-2; i >= 0; i--) {
        	for (int j = n-2; j >= 0; j--) {
        		Flood[i][j] = max(1, min(Flood[i+1][j]-dungeon[i+1][j], Flood[i][j+1]-dungeon[i][j+1]));
        	}
        }
        int result = Flood[0][0]-dungeon[0][0];
        return (result <= 0?1:result);
    }
};

唉,以我這頭腦,如果我是騎士,等想出解法來,可能公主早就掛了吧。