/*
* 题目描述:
* 有一个M*N的梅花桩阵,每个桩都有允许跳跃的最大步数,用户从0.0的位置开始跳跃,
* 允许向右和向下方向跳跃,求最少要跳跃多少次才能达M-1, N-1的位置。无法到达目的地时
* 返回-1.M <= 100, N <= 100,每个桩上允许跳跃的最大步数均为小于10的正整数, 0 表示
* 不允许跳跃到该位置
*
* 输入描述;
* 1、第1行为M和N,用“,”号隔开;
* 2、第2行为M*N的梅花桩(格式参考样例),数组位置为允许跳跃的最大步数,0表示该位置为空,
* 不能跳跃到该位置;
* 输出描述:
* 最少跳跃的步数
* 示例1:
* 输入:
* 3,3
* 3 2 2 0 1 0 1 1 1
* 输出:
* 2
*/
说明:
华为0908第二题,
这里是基于文大佬基础上修改调试的,特此说明
使用方法是DP,使用递归的会超时
这道题就是高配版的leetcode45:45. 跳跃游戏 II
解题思路:
个人理解,一般这种M*N的矩阵问题,可移动方向为上下左右时,一般用DFS,可移动方向只有向右和向下时,一般使用DP,因为可以从左至右、从上至下的更新状态;
动态规划具体思路:
1、初始化:定义一个DP矩阵 m*n,dp[i][j]表示到达(i, j)位置所需要的最少跳跃步数;
(1)由于是更新更小的值在每个dp[i][j]上,所以初始化整个数组为INT_MAX;
(2) 由于出发点是(0, 0), 所以dp[0][0]=0,物理意义为需要0步到达(0, 0)
2、状态转移方程:
该题特殊的地方在于需要进行两重循环更新dp矩阵
对于每个(i, j)位置,根据step = nums[i][j]确定当前位置可以运动的范围, 然后对可运动的范围中的位置进行状态转移:
例如下图的(0, 0)位置,step=3,也就是说其可以跳跃的范围是向右3步之内和向下3步之内,
dp矩阵更新:
对于位置(i, j)向下运动, 横坐标ii范围是[i+1, min(step+i, M-1)],纵坐标不变,状态转移方程为:
dp[ii][j] = min(dp[ii][j], dp[i][j]+1)
向右运动,横坐标不变,纵坐标jj范围是[j+1, min(step+j, N-1)],状态转移方程为:
dp[j][ii] = min(dp[j][ii], dp[i][j]+1)
3、特殊情况处理:
对于nums[i][j]=0的区域,代表不可以跳跃到此地,那么该地域的最少跳跃步数是无限大的,也就是INT_MAX,所以遍历到nums[i][j] = 0 的地域直接跳过;
4、返回值:
返回dp[M-1][N-1]
代码如下:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int solution(vector<vector<int>>& nums) {
int M = nums.size();
int N = nums[0].size();
// dp[i][j]代表到达第i行第j列梅花桩所允许的最少跳跃步数
vector<vector<int>> dp(M, vector<int>(N, INT_MAX));
dp[0][0] = 0;
int step;
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
step = nums[i][j];
if (nums[i][j] == 0) continue;
//if (dp[i][j] == INT_MAX) continue;
// 向下更新
for(int ii = i+1; ii <= min(step+i, M-1); ++ ii){
if (nums[ii][j] == 0) continue;
dp[ii][j] = min(dp[ii][j], dp[i][j] + 1);
}
// 向右更新
for (int jj = j+1; jj <= min(step + j, N-1); ++jj) {
if (nums[i][jj] == 0) continue;
dp[i][jj] = min(dp[i][jj], dp[i][j] + 1);
}
}
}
if (dp[M - 1][N - 1] == INT_MAX) return -1;
return dp[M - 1][N - 1];
}
// 华为机试经常要用到
vector<int> split(string s, char c) {
vector<int> res;
int left = 0;
int idx;
string tmp;
while (s.find(c, left) != s.npos) {
idx = s.find(c, left);
tmp = s.substr(left, idx - left);
res.push_back(atoi(tmp.c_str()));
left = idx + 1;
}
if (left < s.size()) {
tmp = s.substr(left, s.size() - left);
res.push_back(atoi(tmp.c_str()));
}
return res;
}
int main() {
string s;
cin >> s;
vector<int> info = split(s, ',');
int M = info[0], N = info[1];
vector<vector<int>> nums(M, vector<int>(N, 0));
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
cin >> nums[i][j];
}
}
cout << solution(nums) << endl;
}
执行结果如下: