18276 走迷宫2(已更新)
时间限制:1000MS 代码长度限制:10KB
题型: 编程题 语言: G++;GCC;VC
Description
有一个N*M的格子迷宫,1代表该格子为墙,不能通过,0代表可以通过,另外,在迷宫中有一些传送门,走到传送门的入口即会自动被传送到传送门的出口(一次传送算1步)。人在迷宫中可以尝试上下左右四个方向移动。现在给定一个迷宫和所有传送门的出入口,以及起点和终点,问最少多少步可以走出迷宫。如果不能走出迷宫输出“die”。
输入格式
该程序为多CASE,第1行为CASE的数量 每一个CASE,第1行为两个数N(行)和M(列) 然后N行每行M个数 之后是一个数W,为传送门的数量 之后每行一个传送门的入口坐标c1(行),r1(列)和出口坐标c2,r2 之后是起点坐标和终点坐标sc(行) sr(列) ec(行) er(列) 注:传送门出入口和起点坐标和终点坐标不会出现在墙的位置 所有数字不超过100
输出格式
如题
输入样例
2 4 3 011 011 110 110 1 1 0 2 2 0 0 3 2 2 2 01 10 0 0 0 1 1
输出样例
3 die
问题分析:
BFS广度优先搜索,使用队列存储待搜位置,注意边界判断。
该题OJ系统似乎对于超时判断较严,需要尽量精简代码。
以下更新于2024.4.18
上次做的时候其实没有真正理解“避免重复搜索”,还觉得一定要把边界设置为'1'才能避免超时,其实并不需要。
在寻找next位置把已经放进daisou队列中的位置标记为‘1’即可大大减少重复搜索(不过本题解需要在每次循环开始处判断now位置是否为‘2’(传送门入口),只能标记非传送门位置)
代码实现:
2.0:
#include<iostream>
#include<queue>
#define MGsize 105//可修改迷宫大小(不过这么写只能是正方形地图)
using namespace std;
//每个位置基本信息
struct gezi
{
int x;
int y;
int steps;
};
//用于位置移动(确定next)
int xmove[4]={1,0,-1,0};
int ymove[4]={0,1,0,-1};
int main()
{
//多case
int n=0;
cin>>n;
while(n--)
{
char migong[MGsize][MGsize];//迷宫地图
gezi portal[MGsize][MGsize];//传送门对应的传送出口
//读入迷宫地图
int hang,lie;
cin>>hang>>lie;
for(int i=0;i<hang;i++)
{
scanf("%s",migong[i]);
}
//读入传送门信息
int portalnum;
cin>>portalnum;
for(int i=0;i<portalnum;i++)
{
gezi tempin,tempout;
cin>>tempin.x>>tempin.y>>tempout.x>>tempout.y;
portal[tempin.x][tempin.y]=tempout;
migong[tempin.x][tempin.y]='2';//传送门在地图中标记为'2'
}
//读入起点终点信息
gezi sstart,ffinal;
cin>>sstart.x>>sstart.y>>ffinal.x>>ffinal.y;
sstart.steps=0;
//初始化
queue<gezi>daisou;
daisou.push(sstart);
//广度优先搜索
int flag=0;
gezi now,next;
while(!daisou.empty())
{
now=daisou.front();
daisou.pop();
//判断是否到达终点
if(now.x==ffinal.x&&now.y==ffinal.y)
{
flag=1;
break;
}
//判断当前是否为传送门
if(migong[now.x][now.y]=='2')//会堵住这里
{
next=portal[now.x][now.y];//next为传送出口
next.steps=now.steps+1;
daisou.push(next);
migong[next.x][next.y]='1';
}
else
{
for(int i=0;i<4;i++)
{
next.x=now.x+xmove[i];
next.y=now.y+ymove[i];
//边界判断
if(next.x<0||next.y<0||next.x>=hang||next.y>=lie)
{
continue;
}
//该位置不为墙且未访问过
if(migong[next.x][next.y]!='1')
{
next.steps=now.steps+1;//走到next步数为走到now的步数+1
daisou.push(next);
if(migong[next.x][next.y]!='2')///如果是传送门也标记,会堵住上面(判断now是否为传送门)
{
migong[next.x][next.y]='1';//避免该next位置以后再被加入daisou队列
}
}
}
}
migong[now.x][now.y]='1';
}
//flag==1则找到终点
if(flag==1)
{
cout<<now.steps<<endl;
}
else
{
cout<<"die"<<endl;
}
}
return 0;
}
1.0:
#include <iostream>
#include<cstdio>
#include<queue>
using namespace std;
struct node//基础位置节点
{
int x;
int y;
int steps;
};
int main()
{
int n=0,portalnum=0;
struct node sstart,ffinal;//起点、终点位置
int xmove[4]={1,0,-1,0};//用于寻找下一个位置
int ymove[4]={0,1,0,-1};
char migong[102][102];//基本地图,墙为1,空为0.传送门为2
struct node portal[102][102];//传送门所对应的传送位置
for(int i=0;i<102;i++)//初始化migong数组
{
for (int j=0;j<102;j++)
{
migong[i][j]='1';
}
}
/**多case*/
scanf("%d",&n);
while(n--)
{
/**读入迷宫基础信息*/
int hang,lie;
scanf("%d%d",&hang,&lie);
for(int i=1;i<=hang;i++)
{
for(int j=1;j<=lie;j++)//边界设置为“墙”,不使用下标为0的行与列
{
cin>>migong[i][j];
}
}
/**读入传送门信息*/
scanf("%d",&portalnum);
for(int i=0;i<portalnum;i++)
{
struct node TempPortal_Enter;
struct node TempPortal_Exit;
scanf("%d%d",&TempPortal_Enter.x,&TempPortal_Enter.y);
scanf("%d%d",&TempPortal_Exit.x,&TempPortal_Exit.y);
TempPortal_Enter.x++;
TempPortal_Enter.y++;
TempPortal_Exit.x++;
TempPortal_Exit.y++;
portal[TempPortal_Enter.x][TempPortal_Enter.y]=TempPortal_Exit;//将传送门信息保存到portal数组中
migong[TempPortal_Enter.x][TempPortal_Enter.y]='2';//在基本地图中标注传送门
}
/**读入起点终点位置*/
scanf("%d%d",&sstart.x,&sstart.y);
scanf("%d%d",&ffinal.x,&ffinal.y);
sstart.x++;
sstart.y++;
ffinal.x++;
ffinal.y++;
/**初始化*/
queue<struct node>daisou;//建立队列保存待搜索位置
sstart.steps=0;
daisou.push(sstart);
/**探索待搜节点并寻找下一个节点*/
while(!daisou.empty())
{
struct node now,next;
now=daisou.front();
if(now.x==ffinal.x&&now.y==ffinal.y)//到达终点,直接结束
break;
daisou.pop();
if(migong[now.x][now.y]=='2')//遇到传送门
{
next=portal[now.x][now.y];
next.steps=now.steps+1;
migong[next.x][next.y]='1';
migong[now.x][now.y]='1';
daisou.push(next);
}
else
{
for(int j=0;j<4;j++)//朝四个方向的移动
{
next.x=now.x+xmove[j];
next.y=now.y+ymove[j];
if(migong[next.x][next.y]!='1')//该位置未搜索过且不为墙
{
next.steps=now.steps+1;
daisou.push(next);
if(migong[next.x][next.y]!='2')//若next位置非传送门非终点,将其标记无需重复检查
migong[next.x][next.y]='1';
}
}
}
}
if (daisou.empty())//未找到终点
printf("die\n");
else
{
node eend=daisou.front();
printf("%d\n",eend.steps);
}
}
return 0;
}