双向BFS

小A和小B

题意:
小A和小B在n∗m迷宫的两个不同位置
迷宫中有障碍物迷宫中有障碍物
小A每分钟可以走周围八个方向一次小A每分钟可以走周围八个方向一次
小B每分钟可以走上下左右四个方向两次小B每分钟可以走上下左右四个方向两次
问两个人最早什么时候可以相遇,不能相遇输出-1问两个人最早什么时候可以相遇,不能相遇输出−1

第一行两个整数N,M分别表示迷宫的行和列。
接下来一个N×M的矩阵(1 < N,M < 1000)
其中"C"表示小A的位置,"D"表示小B的的位置,
"#"表示不可通过的障碍,"."则是可以正常通过的位置。
字符用空格隔开

样例输入:

4 5
. . . . .
. # # # .
. . . # D
. . C # .

样例输出:

YES
3

题解:
将两个人的初始位置放入两个队列,记为第0秒
然后按各自的方向进行BFS搜索并分别记录下行走中可以到达的点,若其中一人目前走到的点是另一人曾经走过的,则说明他们俩必定相遇

代码:

#pragma GCC optimize(3,"Ofast","inline")
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e3 + 10;
const double eps = 1e-8;
const int inf = 1e9;
const double PI = acos(-1.0);

int n, m;
int dir[8][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
bool vis[2][1005][1005];
char s[1005][1005];

queue<pii> q[2];

bool bfs(int x){
  int sz = q[x].size();
  while(sz --){
    auto t = q[x].front();
    q[x].pop();
    for(int i = 0; i < 8 - 4 * x; i ++){
      int nx = t.first + dir[i][0];
      int ny = t.second + dir[i][1];
      if(nx < 0 || nx >= n || ny < 0 || ny >= m || s[nx][ny] == '#')
        continue;
      if(vis[1 - x][nx][ny])  return true;
      if(!vis[x][nx][ny]){
        q[x].push(make_pair(nx, ny));
        vis[x][nx][ny] = true;
      }
    }
  }
  return false;
}


int solve(){
  int ans = 0;
  while(!q[0].empty() || !q[1].empty()){
    ans ++;
    if(bfs(0))  return ans;
    if(bfs(1))  return ans;
    if(bfs(1))  return ans;
  }
  return -1;
}


int main()
{
  scanf("%d%d", &n, &m);
  getchar();
  memset(vis, false, sizeof(vis));
  for(int i = 0; i < n; i ++){
    for(int j = 0; j < m; j ++){
      scanf("%c", &s[i][j]);
      if(s[i][j] == 'C'){
        q[0].push(make_pair(i, j));
        vis[0][i][j] = true;
      }
      if(s[i][j] == 'D'){
        q[1].push(make_pair(i, j));
        vis[1][i][j] = true;
      }
      getchar();
    }
  }

  int ans = solve();
  if(ans == -1) puts("NO");
  else{
    puts("YES");
    printf("%d\n", ans);
  }
  return 0;
}

HDU-3085
题意:
有一个n∗m的矩阵,有三类东西
1.Z一秒可以扩散到两步以内的范围,每一步都可以走四个方向, 可以穿墙。
2.M一秒可以走3步, 每一步都可以是四个方向, 不可穿墙。
3.G一秒可以走1步, 每一步都可以是四个方向, 不可穿墙。
求M和G是否可以相遇。

题解:
双向BFS + 曼哈顿距离
由于Z可以穿墙, 所以对于整个图来说,Z畅通无阻, 因此可以利用曼哈顿距离来判断M和G是否会被抓到,避免了Z加入队列的麻烦。

代码:

#pragma GCC optimize(3,"Ofast","inline")
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e3 + 10;
const double eps = 1e-8;
const int inf = 1e9;
const double PI = acos(-1.0);

int t, n, m;
int dir[4][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
char s[805][805];
bool vis[2][805][805];
int ans = 0;

pii G, M, Z[2];
queue<pii> q[2];

bool judge(int x, int y){
  if(x < 0 || x >= n || y < 0 || y >= m || s[x][y] == 'X')
    return false;
  if(abs(x - Z[0].first) + abs(y - Z[0].second) <= 2 * ans)
    return false;
  if(abs(x - Z[1].first) + abs(y - Z[1].second) <= 2 * ans)
    return false;
  return true;
}


bool bfs(int x){
  int sz = q[x].size();
  while(sz --){
    auto t = q[x].front();
    q[x].pop();
    if(!judge(t.first, t.second)) continue;
    for(int i = 0; i < 4; i ++){
      int nx = t.first + dir[i][0];
      int ny = t.second + dir[i][1];
      if(!judge(nx, ny))  continue;
      if(vis[1 - x][nx][ny]) return true;
      if(!vis[x][nx][ny]){
        q[x].push(make_pair(nx, ny));
        vis[x][nx][ny] = true;
      }
    }
  }
  return false;
}

int solve(){

  ans = 0;
  while(!q[0].empty())  q[0].pop();
  while(!q[1].empty())  q[1].pop();
  memset(vis, false, sizeof(vis));

  q[0].push(M);
  q[1].push(G);
  vis[0][M.first][M.second] = true;
  vis[1][G.first][G.second] = true;

  while(!q[0].empty() || !q[1].empty()){
    ans ++;
    if(bfs(0) == 1) return ans;
    if(bfs(0) == 1) return ans;
    if(bfs(0) == 1) return ans;
    if(bfs(1) == 1) return ans;
  }
  return -1;
}

int main()
{
  scanf("%d", &t);

  while(t --){
    int k = 0;
    scanf("%d%d",&n,&m);
    getchar();
    for(int i = 0; i < n; i ++){
      scanf("%s", s[i]);
      for(int j = 0; j < m; j ++){
        if(s[i][j] == 'M'){
          M = make_pair(i, j);
        }
        else if(s[i][j] == 'G'){
          G = make_pair(i, j);
        }
        else if(s[i][j] == 'Z'){
          Z[k ++] = make_pair(i, j);
        }
      }
      getchar();
    }
    int ans = solve();
    printf("%d\n", ans);
  }
  return 0;
}
点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注