面试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;}