【秋招机试真题】华为机试0908-梅花桩

/*
*    题目描述:
*        有一个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;
}

执行结果如下:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值