LeetCode 174: Dungeon Game 解题与思考

LeetCode 174: Dungeon Game 解题与思考

[原题链接]

题目描述

给一个M×N的地图,每个格子有一个数字,负数为扣减生命值,正数为增加生命值,当生命值小于等于0时角色死亡,求解从地图左上角到右下角所需的最小生命值。

思路

题目限定了骑士只能往右或者下走,给我们提供了很大方便。
不过直接从左上DP到右下不是很理智,因为没有确定初始生命值,不能很好地把握角色死亡的标准。
然而在到达右下角时,为了解最优,角色一定剩下1血,故应该从右下角DP回左上角。
我们用一个二维数组HP[m][n]记录从某一格到右下角需要的生命值,假设当前地图的数字为dungeon[i][j],那么有如下递推式:

HP[i][j]+dungeon[i][j]=min(HP[i][j+1],HP[i+1][j])

HP[i][j]=min(HP[i][j+1],HP[i+1][j])dungeon[i][j]

也就是说,当前格子结算完毕后,我们朝着所需生命值更少的方向前进。
不过我们需要考虑dungeon[i][j]十分大的情况,也就是说只要能成功到达这格就能到达目标地点,此时HP[i][j]直接为1。

算法

1、为了计算方便,初始化数组HP[M+1][N+1],HP[M][0~N-2] =HP[0~M - 2][N] = 2147483647,让DP不会跑到地图外;HP[M][N-1] = HP[M-1][N] = 1,让右下角正确剩余1血。
2、从右下角到左上角,按照如下方法更新:

HP_need=min(HP[i][j+1],HP[i+1][j])dungeon[i][j]

  • 假如 HP_need<=0 ,那么 HP[i][j]=1 ;
  • 假如 HP_need>0 ,那么 HP[i][j]=HP_need ;

3、最后返回 HP[0][0]

代码

#include <iostream>
#include <vector>
#include <stdlib.h>
#include<string.h>
using namespace std;


class Solution {
    int min(int x, int y) {
        return (x < y) ? x : y;
    }
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
        int M = dungeon.size();
        int N = dungeon[0].size();
        int *health_need = (int*)malloc((M + 1) * (N + 1) * sizeof(int));
        memset(health_need, 0, (M + 1) * (N + 1) * sizeof(int));
        for ( int m = M - 2; m >= 0; m-- ) {
            health_need[m * (N + 1) + N] = 2147483647;
        }
        for ( int n = N  - 2; n >= 0; n-- ) {
            health_need[M * (N + 1) + n] = 2147483647;
        }
        health_need[M * (N + 1) + N - 1] = 1;
        health_need[(M - 1) * (N + 1) + N] = 1;
        for ( int m = M - 1; m >= 0; m-- ) {
            for ( int n = N - 1; n >= 0; n-- ) {
                int current_health = min(health_need[m * (N + 1) + n + 1], health_need[(m + 1) * (N + 1) + n]) - dungeon[m][n];
                health_need[m*(N + 1) + n] = (current_health <= 0) ? 1 : current_health;
            }
        }
        int result = health_need[0];
        free(health_need);
        return result;
    }
};

思考

一开始并没有考虑补右边和下边那一条大边,结果写起来很麻烦,最后才想到这么做,实属惭愧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值