问题描述 小明天天都要练功,练功中的重要一项是梅花桩。 小明练功的梅花桩排列成 n 行 m 列,相邻两行的距离为 1,相邻两列的距离也为 1。 小明站在第 1 行第 1 列上,他要走到第 n 行第 m 列上。小明已经练了一段时间,他如今能够一步移动不超过 d 的距离(直线距离)。 小明想知道,在不掉下梅花桩的状况下,本身最少要多少步能够移动到目标。 输入格式 输入的第一行包含两个整数 n, m,分别表示梅花桩的行数和列数。 第二行包含一个实数 d(最多包含一位小数),表示小明一步能够移动的距离。 输出格式 输出一个整数,表示小明最少多少步能够到达目标。 样例输入 3 4 1.5 样例输出 3 评测用例规模与约定 对于 30% 的评测用例,2 <= n, m <= 20,1 <= d <= 20。 对于 60% 的评测用例,2 <= n, m <= 100,1 <= d <= 100。 对于全部评测用例,2 <= n, m <= 1000,1 <= d <= 100。
使用宽度优先搜索,从(1,1)开始搜索。用 x 表示行,用 y 表示列。d 为用户输入的能够移动的距离ios
(x + d, y)
;(x, y + d)
;代码里使用了bool booked[N][N]
二维数组用来表示已经走过的(x, y)
点,避免重复的搜索。因为输入的步数 d 可能会很大,斜着走更加容易走到终点,把斜着走符合条件的点先入队,会避免走那些更远的点,从而达到节省时间的效果。数组
#include <iostream> #include <algorithm> #include <cmath> #include <queue> #define N 10001 using namespace std; const double minDis = sqrt(2); int n, m; double d; bool booked[N][N]; struct Point { int x, y, step; }; void bfs () { // d1 横竖着走最大的移动距离 // d2 斜着走最大的移动距离 int d1 = (int)d; queue<struct Point> Q; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) booked[i][j] = false; struct Point p; p.x = 1; p.y = 1; p.step = 0; Q.push(p); while (Q.size()) { struct Point top = Q.front(); Q.pop(); if (top.x >= n && top.y >= m) { cout << top.step << endl; break; } struct Point p1, p2, p3; // 斜着走 // 斜着走最小都须要跟号 2 的长度 if (d >= minDis) { for (int i = 1; i <= d; i++) { for (int j = 1; j <= d; j++) { int temp = j * j + i * i; if (temp <= d * d) { struct Point p3; p3.x = j + top.y; p3.y = i + top.x; if (!booked[p3.x][p3.y]) { booked[p3.x][p3.y] = true; p3.step = top.step + 1; Q.push(p3); } } } } } p1.x = top.x + d1; if (!booked[p1.x][top.y] && top.x < n) { // 向下走 p1.y = top.y; p1.step = top.step + 1; booked[p1.x][p1.y] = true; Q.push(p1); } p2.y = top.y + d1; if (!booked[top.x][p2.y] && top.y < m) { // 向右走 p2.x = top.x; p2.step = top.step + 1; booked[p2.x][p2.y] = true; Q.push(p2); } } } int main () { cin >> n >> m; cin >> d; bfs(); return 0; }