問題描述 小明天天都要練功,練功中的重要一項是梅花樁。 小明練功的梅花樁排列成 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; }