leetcode174. 地下城游戏

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快到达公主,骑士决定每次只向右或向下移动一步。

编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。

例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。

-2 (K) -3 3
-5 -10 1
10 30 -5 (P)

说明:
    
    骑士的健康点数没有上限。
    任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。
链接:https://leetcode-cn.com/problems/dungeon-game

【思路】

这道题和一般dp题目不一样的地方就是选项中有正数也有负数,而不仅选最大路径值或者最小路径值。

在骑士行走的过程中,所需健康点数=后续过程所需要的健康点数+当前房间所需要的健康点数(也可能不需要,或许还能获得健康点数)。如果能想到上面这点,其实状态方程已经很好判断了。其中要注意的是健康点数一直都是正整数,所以最小值为1.

我们只需要记录走到每个房间时所需要的健康点数即可。并且如果发现当前房间的数值要比后续需要的健康点数还要大,那么当前健康点数补偿为1(最小值)。

int min(int a,int b){
    return a<b?a:b;
}
int calculateMinimumHP(int** dungeon, int dungeonSize, int* dungeonColSize){
    int i,j,max[dungeonSize+1][*dungeonColSize+1];
    if(dungeon==NULL||dungeonSize==0||*dungeonColSize==0){
        return 0;
    }
    if(dungeon[dungeonSize-1][*dungeonColSize-1]<=0)
        max[dungeonSize-1][*dungeonColSize-1]=-dungeon[dungeonSize-1][*dungeonColSize-1]+1;
    else
        max[dungeonSize-1][*dungeonColSize-1]=1;
   
    for(i=dungeonSize-2;i>=0;i--){//先判断最后一行
        if(dungeon[i][*dungeonColSize-1]<=0)
            max[i][*dungeonColSize-1]=max[i+1][*dungeonColSize-1]-dungeon[i][*dungeonColSize-1];
        else{
            max[i][*dungeonColSize-1]=max[i+1][*dungeonColSize-1]-dungeon[i][*dungeonColSize-1];
            if(max[i][*dungeonColSize-1]<1)
                max[i][*dungeonColSize-1]=1;
        }
        
    }
    for(j=*dungeonColSize-2;j>=0;j--){//先判断最后一列
        if(dungeon[dungeonSize-1][j]<=0)
        max[dungeonSize-1][j]=max[dungeonSize-1][j+1]-dungeon[dungeonSize-1][j];
        else{
            max[dungeonSize-1][j]=max[dungeonSize-1][j+1]-dungeon[dungeonSize-1][j];
            if(max[dungeonSize-1][j]<1)
                max[dungeonSize-1][j]=1;
        }
    }
    for(i=dungeonSize-2;i>=0;i--){//依次从底向上填充
        for(j=*dungeonColSize-2;j>=0;j--){
            if(dungeon[i][j]<=0)//取向下或者向右z走最小的补偿,再去判断当前的补偿,然后计算总补偿
                max[i][j]=min(max[i+1][j],max[i][j+1])-dungeon[i][j];
            else{
                max[i][j]=min(max[i+1][j],max[i][j+1])-dungeon[i][j];
                if(max[i][j]<1)//很有意思,由于健康点数一定是正整数,因此对于当前的健康点数如果小于1,那么赋值为1,为什么会小于1?是因为当前所在的房间是一个比较大的正整数,而且当前的正整数要比后面所需要的健康点数还要大。
                max[i][j]=1;
            }
        }
    }

    return max[0][0];
}

简化为一维数组形式:可自己画图模拟赋值过程,依次从后往前按照列进行赋值时,只需要记录后一列数据即可。

int min(int a,int b){
    return a<b?a:b;
}
int calculateMinimumHP(int** dungeon, int dungeonSize, int* dungeonColSize){
    int i,j,max[dungeonSize+1];
    if(dungeon==NULL||dungeonSize==0||*dungeonColSize==0){
        return 0;
    }
    if(dungeon[dungeonSize-1][*dungeonColSize-1]<=0)//初始化终点
        max[dungeonSize-1]=-dungeon[dungeonSize-1][*dungeonColSize-1]+1;
    else
        max[dungeonSize-1]=1;
   
    for(i=dungeonSize-2;i>=0;i--){//初始化最后一列
        max[i]=max[i+1]-dungeon[i][*dungeonColSize-1];
        if(max[i]<1)
            max[i]=1;
    }
    for(j=*dungeonColSize-2;j>=0;j--){//从最后一列依次往前赋值,根据状态转化方程,只需要记录后一列数据即可,这样成功将二维数组简化为一维数组
        max[dungeonSize-1]=max[dungeonSize-1]-dungeon[dungeonSize-1][j];
        if(max[dungeonSize-1]<1)
            max[dungeonSize-1]=1;
        for(i=dungeonSize-2;i>=0;i--){
            max[i]=min(max[i+1],max[i])-dungeon[i][j];
            if(max[i]<1)
                max[i]=1;
        }
    }
    return max[0];
}
发布了129 篇原创文章 · 获赞 105 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/sunshine_lyn/article/details/104201773