面试OR笔试14——最小体力值

来源:互联网 发布:黑猫警长细思极恐 知乎 编辑:程序博客网 时间:2024/06/04 08:29

1 题目及要求

1.1 题目描述

一个战棋类游戏,角色只能向右和下两个方向移动且移动需要消耗体力。游戏地图上被分为M*N个格子,当角色移动到某个格子上时,行动力就会加上格子上的值K (-100~100),当行动力<=0时游戏失败。求从地图左上角移动到地图右下角至少需要多少起始行动力。(玩家初始化到起始的左上角格子时也需要行动体力)

 

1)输入:

第一行,输入格子行数和列数(格式为 M N);0 < M, N< 1000

第二行到M+1行,每行输入N个数作为格子的K值,中间以空格分隔; -100 < K < 100

 

2)输出:

初始最小行动力

 

3)输入范例:

2 3

-2 -3 3

-5 -10 1

 

4)输出范例:

6

 

1.2 测试用例

1)测试1

2 3

-2 -3 3

-5 -10 1

答案为6

 

2)测试2

2 3

1 -3 10

1 0 -2

答案为1

 

3)测试3

2 3

1 -3 10

1 0 -5

答案为3

 

2 解答

2.1 题目分析

用动态规划。设v[k1][k2] 为K值矩阵的元素,dt[k1][k2]表示由(k1, k2)位置到右下角的最小行动力,则该位置的最小行动力由三个因素决定:

1)该位置本身需要的最小行动力1 – v[k1][k2],如论向右还是向下都至少不少于该值

2)到右边格子需要的最小行动力,max(1 – v[k1][k2], dt[k1][k2+1]-v[k1][k2])

3)到下边格子需要的最小行动力,max(1 – v[k1][k2], dt[k1+1][k2]-v[k1][k2])

该位置的值就是2和3中的最小值(如果都有的话)。

则很显然有递推关系:

dt[k1][k2] =min(max(1,dt[k1][k2+1]),max(1,dt[k1+1][k2]))-v[k1][k2];

 

由于到最后的位置不能没有体力值。所以初始值dt[M-1][N-1] = 1-v[M-1][N-1]

 

2.2 代码

#include <iostream>#include <vector>#include <string>#include <algorithm>using namespace std;int minBlood(const vector<vector<int> > &v){if(v.size()<1 || v[0].size()<1) return 0;int r(v.size()),c(v[0].size());vector<vector<int> > dt(v);dt[r-1][c-1] = 1-v[r-1][c-1];for (int k1(r-2),k2(c-1);-1 < k1;--k1) dt[k1][k2] = max(1,dt[k1+1][k2])-v[k1][k2];for (int k1(r-1),k2(c-2);-1 < k2;--k2) dt[k1][k2] = max(1,dt[k1][k2+1])-v[k1][k2];for (int k1(r-2);-1 < k1;--k1)for (int k2(c-2);-1 < k2;--k2)dt[k1][k2] = min(max(1,dt[k1][k2+1]),max(1,dt[k1+1][k2]))-v[k1][k2];return dt[0][0];}int main(int argc, const char * argv[]) {int r,c;cin >> r >> c;vector<vector<int> > v(r,vector<int>(c,0));for (int k1(0); k1 < r;++k1)for (int k2(0);k2 <c;++k2) cin >> v[k1][k2];cout << minBlood(v);    return 0;}