洛谷 P1825

题目链接

题目大意

给出一个n*m的矩阵,里面包含了起点位置和终点位置和所有传送门的位置,现在有一头牛在起点,他可以往上下左右四个方向行动,每行动一格将花费一个单位的时间,使用传送门不需要时间(传送门用大写字母A~W表示),传送门以一对的形式存在。最后就是输出从起点到终点所花费的最小时间。

解题思路

首先明确,这是一道广搜的题目,因为只用找一条从起点到终点的用时最短路。那么我们来考虑一下,本道题和普通的广搜迷宫有什么不同。显而易见,唯一的不同就是多了一堆双向传送的传送门,所以我们只要在输入的时候记录一下每一对传送门的位置,然后在广搜遇到的时候再把下一个点修改为对应传送门的坐标就好了,其余的东西和广搜模板都是一样的。

上代码!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#define ll long long
#define pi acos(-1)
#define inf 0x3f3f3f3f
#define pii pair<int, int>
#define mp(a, b) make_pair(a, b)
#define piii pair<pii, int>
#define min(a, b) (a < b ? a : b)
#define max(a, b) (a > b ? a : b)
#define uf(a, b, i) for (register int i = (a); i <= (b); ++i)
#define df(a, b, i) for (register int i = (a); i >= (b); --i)
using namespace std;
inline ll read() {
	ll x = 0, f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}
const int N = 303;
int n, m, sx, sy, ex, ey;
char s[N][N];
bool vis[N][N];
int cnt[N][N];
int a[27][2][2];
int cx[] = {0, 0, 1, -1};
int cy[] = {1, -1, 0, 0};
queue<pii> q;
pii p;
inline bool right(int x, int y) {
  return (x > 0 && x <= n && y > 0 && y <= m && !vis[x][y] && s[x][y] != '#');
}
void bfs(int x, int y) {
  vis[x][y] = 1;
  q.push(mp(x, y));
  while (!q.empty()) {
    p = q.front();
    uf(0, 3, i) {
      int xx = p.first + cx[i];
      int yy = p.second + cy[i];
      if (right(xx, yy)) {
        if (s[xx][yy] >= 'A' && s[xx][yy] <= 'Z') {
          int posx = xx, posy = yy;
          if (posx == a[s[xx][yy]-'A'][0][0] && posy == a[s[xx][yy]-'A'][0][1])
            posx = a[s[xx][yy]-'A'][1][0], posy = a[s[xx][yy]-'A'][1][1];
          else posx = a[s[xx][yy]-'A'][0][0], posy = a[s[xx][yy]-'A'][0][1];
          if (cnt[posx][posy] == 0) cnt[posx][posy] = cnt[p.first][p.second] + 1;
          else cnt[posx][posy] = min(cnt[posx][posy], cnt[p.first][p.second] + 1);
          q.push(mp(posx, posy));
        } else {
          vis[xx][yy] = 1;
          cnt[xx][yy] = cnt[p.first][p.second] + 1;
          if (xx == ex && yy == ey) {
            printf("%d\n", cnt[xx][yy]);
            while (q.size()) q.pop();
            return ;
          }
          q.push(mp(xx, yy));
        }
      }
    }
    q.pop();
  }
}
int main() {
  n = read(); m = read();
  uf(1, n, i) {
    scanf("%s", s[i]+1);
    uf(1, m, j) {
      if (s[i][j] == '@') sx = i, sy = j;
      else if (s[i][j] == '=') ex = i, ey = j;
      else if (s[i][j] >= 'A' && s[i][j] <= 'Z') {
        if (a[s[i][j]-'A'][0][0] == 0) a[s[i][j]-'A'][0][0] = i, a[s[i][j]-'A'][0][1] = j;
        else a[s[i][j]-'A'][1][0] = i, a[s[i][j]-'A'][1][1] = j;
      }
    }
  }
  bfs(sx, sy);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值