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;
}
相关文章
相关标签/搜索