洛谷P1825-[USACO11OPEN]Corn Maze S(BFS)
题目描述:
去年秋天,奶牛们去参观了一个玉米迷宫,迷宫里有一些传送装置,可以将奶牛从一点到另一点进行瞬间转移。这些装置可以双向使用:一头奶牛可以从这个装置的起点立即到此装置的终点,同时也可以从终点出发,到达这个装置的起点。如果一头奶牛处在这个装置的起点或者终点,这头奶牛就必须使用这个装置。
玉米迷宫的外部完全被玉米田包围,除了唯一的一个出口。
这个迷宫可以表示为N×M的矩阵(2 ≤ N ≤ 300; 2 ≤ M ≤ 300),矩阵中的每个元素都由以下项目中的一项组成:
玉米,这些格子是不可以通过的。
草地,可以简单的通过。
一个装置的结点,可以将一头奶牛传送到相对应的另一个结点。
出口
奶牛仅可以在相邻两个格子之间移动,要在这两个格子不是由玉米组成的前提下才可以移动。奶牛能在一格草地上可能存在的四个相邻的格子移动。从草地移动到相邻的一个格子需要花费一个单位的时间,从装置的一个结点到另一个结点需要花费0个单位时间。
被填充为玉米的格子用“#”表示,草地用“.”表示,每一对装置的结点由相同的大写字母组成“A-Z”,且没有两个不同装置的结点用同一个字母表示,出口用“=”表示。
Bessie在这个迷宫中迷路了,她知道她在矩阵中的位置,将Bessie所在的那一块草地用“@”表示。求出Bessie需要移动到出口处的最短时间。
例如以下矩阵,N=5,M=6:
###=##
#.W.##
#.####
#aaa@qq.com##
######
唯一的一个装置的结点用大写字母W表示。
最优方案为:先向右走到装置的结点,花费一个单位时间,再到装置的另一个结点上,花费0个单位时间,然后再向右走一个,再向上走一个,到达出口处,总共花费了3个单位时间。
输入格式:
第一行:两个用空格隔开的整数N和M;
第2-N+1行:第i+1行描述了迷宫中的第i行的情况(共有M个字符,每个字符中间没有空格。)
输出格式:
一个整数,表示Bessie到达终点所需的最短时间。
样例输入:
5 6
###=##
#.W.##
#.####
#aaa@qq.com##
######
样例输出:
3
AC Code:
#include<bits/stdc++.h>
using namespace std;
#define N 510
char s[N][N];//存入地图
int a[N][N];//对地图进行相应的转换
bool vis[N][N];//标记数组
int n,m,sx,sy,ex,ey,mx,my,xx,yy,head,tail;
int dx[]={0,0,1,-1};//两个方向数组
int dy[]={1,-1,0,0};
struct node {
int x,y,step;
}q[N*N];//模拟队列
void find(int x,int y) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(!(i==x&&j==y)) {//搜索一个传送门对应的另一个传送门的位置
if(a[i][j]==a[x][y]) {
xx=i;//获取另一个传送门的坐标
yy=j;
return ;
}
}
}
}
}
int main() {
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
scanf(" %c",&s[i][j]);//%前面的空格确保地图完整输入
//将可以走的地方都用a数组标记为1,不能走的标记为0
if(s[i][j]=='.') {//草地可以走
a[i][j]=1;
}else if(s[i][j]=='@') {//起点可以走
sx=i;
sy=j;
a[i][j]=1;
}else if(s[i][j]=='=') {//出口可以走
ex=i;
ey=j;
a[i][j]=1;
}else if(s[i][j]>='A'&&s[i][j]<='Z') {//传送门可以走
a[i][j]=s[i][j];
}else {//玉米格子不能走
a[i][j]=0;
}
}
}
memset(vis,false,sizeof(vis));//清空标记数组
vis[sx][sy]=true;//对起点进行标记
head=tail=1;//队头队尾初始化
q[head].x=sx;//起点入队
q[head].y=sy;
q[head].step=0;//步数为0
tail++;//队尾向后移动一格
while(head<tail) {//保证队列不为空
if(a[q[head].x][q[head].y]>='A'&&a[q[head].x][q[head].y]<='Z') {//判断此时是否走到传送门
find(q[head].x,q[head].y);//寻找另一个传送门的坐标
q[head].x=xx;//位置坐标更新为另一个传送门
q[head].y=yy;
}
for(int i=0;i<4;i++) {//四个方向搜索
int tx=q[head].x+dx[i];
int ty=q[head].y+dy[i];
//不越界,这个点可以走,并且没有被访问过
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&a[tx][ty]!=0&&vis[tx][ty]==false) {
vis[tx][ty]=true;//标记该点
q[tail].x=tx;//该点入队
q[tail].y=ty;
q[tail].step=q[head].step+1;//步数+1
if(tx==ex&&ty==ey) {//走到出口
printf("%d\n",q[tail].step);//输出此时的步数
return 0;//直接返回
}
tail++;//新的点入队,队尾向后移动一格
}
}
head++;//没有走到出口,队头向后移动一格,继续下一个点的搜索
}
return 0;
}