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 为用户输入的可以移动的距离

  • 往下搜索(x + d, y);
  • 往右搜索(x, y + d)

由于可以斜着走,我们需要计算传入的距离 d,是否能够斜着走多少,也就是 i 从 1 开始算斜边的距离,找到一个斜边的距离大于 d 后,返回 i - 1。i - 1表示,斜着走 x 和 y 分别加多少距离。

  • 斜着搜索(x + (i - 1), y + (i - 1))

注意,如果 i - 1 为 0 的话,就表示不能斜着走了。

代码里使用了bool booked[N][N]二维数组用来表示已经走过的(x, y)点,避免重复的搜索。

代码

#include 
#include 
#include 
#include 
#define N 10001

using namespace std;

int n, m;
double d;
bool booked[N][N];
struct Point {
  int x, y, step;
};

int max_d (double d) {
  double i = 0, max_d = 0;

  while (max_d < d) {
    i++;
    max_d = sqrt((i * i) + (i * i));
  }

  return (int)(i - 1);
}

void bfs () {
  // d1 横竖着走最大的移动距离
  // d2 斜着走最大的移动距离
  int d1 = (int)d, d2 = max_d(d);
  queue Q;

  // printf("d1 = %d, d2 = %d\n", d1, d2);

  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();

    // printf("x = %d, y = %d, step = %d\n", top.x, top.y, top.step);

    if (top.x >= n && top.y >= m) {
      cout << top.step << endl;
      break;
    }

    struct Point p1, p2, p3;
    p1.x = top.x + d1;
    
    if (!booked[p1.x][top.y]) {
      // 向下走
      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]) {
      // 向右走
      p2.x = top.x;
      p2.step = top.step + 1;
      booked[p2.x][p2.y] = true;
      Q.push(p2);
    }

    // 斜着走
    p3.x = top.x + d2;
    p3.y = top.y + d2;
    if (d2 > 0 && !booked[p3.x][p3.y]) {
      p3.step = top.step + 1;
      booked[p3.x][p3.y] = true;
      Q.push(p3);
    }
  }
}

int main () {
  cin >> n >> m;
  cin >> d;

  bfs();

  return 0;
}

你可能感兴趣的:(蓝桥杯,算法)