2020藍橋杯校內賽-梅花樁-搜索

題面

問題描述
  小明天天都要練功,練功中的重要一項是梅花樁。
  小明練功的梅花樁排列成 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)
  • 斜着搜索:從當前點 p1(從隊頭取出)出發,找另一個點 p2,符合 p1p2 的距離的要小於 d*d 的點 p2 入隊。

代碼裏使用了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;
}
相關文章
相關標籤/搜索