新鲜热乎的某厂笔试最后一题。
题目描述
有一个 n * m 个格子的矩阵mp时不时会冒出一些地鼠。mp[i][j] 表示每过 mp[i][j] 的时间第 i 行第 j 列的格子会冒出一只地鼠。
初始时,时间为0,你在第1行第1列格子处,每秒你必须向上下左右四个方向移动一格,不能走出矩阵外。
作为一个合格的打地鼠玩家,如果这一秒你从格子 a 走到格子 b ,下一秒你不能从格子 b 走到格子 a 。如果你走到一个格子的时候,这里刚好冒出一只地鼠,你就可以打一下地鼠。
你的终点是第n行第m列的格子,给你 t 秒时间,问你最多打几下地鼠。
最后你必须到达终点,如果第t秒时你不在终点,算作打了0次地鼠。
输入描述
第一行三个整数n,m,t
接下来n行,每行m个整数表示矩阵mp[i][j]。
2 <= n,m <= 10,1 <= t,mp[i][j] <= 1000
输出描述
输出一行一个整数表示答案
示例:
输入
2 2 6
1 1
1 1
输出
0
说明
一种行走方案是 (1, 1) -> (1, 2) -> (2, 2) -> (2, 1) -> (1, 1) -> (1, 2) -> (2, 2) ,每步都可以打一下地鼠。
解题思路
此题本质上是一个四维动态规划问题,时间、方向、地图横坐标和纵坐标各为一维。个人认为因为移动的范围受到时间限制,如果直接暴力遍历四维数组有过多冗余计算,也不方便剪枝优化。因为题意核心是最优路径查找,只是不用输出各个路径节点,所以可以运用类似各种寻路算法的思想,采用图的广度优先遍历的方法,通过维护更新一个玩家状态的队列的方式来求得结果。
C++实现代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
enum Direction
{
eEast,
eWest,
eNorth,
eSouth,
eStart
};
struct State
{
int t;
int i;
int j;
Direction from;
int score;
State(int t_, int i_, int j_, Direction from_, int score_) :t(t_), i(i_), j(j_), from(from_), score(score_){}
};
void WhacAMole()
{
int n, m, t;
cin >> n >> m >> t;
vector<vector<int>> mp(n, (vector<int>)(m));
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; j++)
{
cin >> mp[i][j];
}
}
int ans = 0;
queue<State> q;
//根据题意每次必须移动一格且不能原路返回,所以默认mp大小至少是2 x 2
//且默认起点在(0,0),所以先把(0,1),(1,0)入队
q.push(State(1, 1, 0, eNorth, (1 % mp[1][0] == 0)));
q.push(State(1, 0, 1, eEast, (1 % mp[0][1] == 0)));
while (!q.empty())
{
State cur = q.front();
q.pop();
if (cur.i == n - 1 && cur.j == m - 1 && cur.t == t) //默认终点位置是(n-1, m -1), 且必须t时刻正好走到终点才可以
{
ans = max(ans, cur.score);
}
int t_new = cur.t + 1;
if (t_new > t)
continue;
if (cur.i > 0 && cur.from != eNorth) //是否可向上走
{
int i_new = cur.i - 1;
int j_new = cur.j;
if (n - 1 - i_new + m - 1 - j_new <= t - cur.t) //如果当前位置在剩余时间内到达不了终点则略过
{
q.push(State(t_new, i_new, j_new, eSouth, cur.score + (t_new % mp[i_new][j_new] == 0))); //t_new % mp[i_new][j_new]为0说明代表当前位置计时已到
}
}
if (cur.i < n - 1 && cur.from != eSouth)
{
int i_new = cur.i + 1;
int j_new = cur.j;
if (n - 1 - i_new + m - 1 - j_new <= t - cur.t)
{
q.push(State(t_new, i_new, j_new, eNorth, cur.score + (t_new % mp[i_new][j_new] == 0)));
}
}
if (cur.j > 0 && cur.from != eEast)
{
int i_new = cur.i;
int j_new = cur.j - 1;
if (n - 1 - i_new + m - 1 - j_new <= t - cur.t)
{
q.push(State(t_new, i_new, j_new, eWest, cur.score + (t_new % mp[i_new][j_new] == 0)));
}
}
if (cur.j < m -1 && cur.from != eWest)
{
int i_new = cur.i;
int j_new = cur.j + 1;
if (n - 1 - i_new + m - 1 - j_new <= t - cur.t)
{
q.push(State(t_new, i_new, j_new, eEast, cur.score + (t_new % mp[i_new][j_new] == 0)));
}
}
}
cout << ans << endl;
}