【洛谷p1605】迷宫
(还记得我昨天大概没人看到的博客(我删辽)吗qwq,2019.4.14下午交的qwq
那篇博客大致内容就是:我提交楼上这道题,交了好久好久好久好久
现在我告诉你,那次评测还N/A着呢qwq)
tqlqwq
回归正题qwq,今天是来写题解的:
算法标签嘤嘤嘤:
它幸好没出dfs,要不然我非要打死把这个题放在bfs(还是由简单到困难的第一个题的wz)小姐姐,伪装成后面没东西的样子qwq
行吧让我们宽广的搜索吧qwq:
其实这道题更像是个搜索回溯,每走一步可以退回原状态来看原状态是否还有符合的,但是我们练的是bfs嘛对不对,当然要写bfs了(不会写搜索回溯)
但是bfs写起来也是真的不简单啊qwq,因为要考虑到回溯qwq,所以感觉以下代码更像是一个回溯的bfsqwq;相信大家如果按bfs的模(mu)板交的话:
//代码没ac
#include<iostream> #include<queue> #include<cstdio> #include<algorithm> using namespace std; int n,m,t,sx,sy,fx,fy,x,y,ans; bool b[110][110]; int dx[4]={1,0,-1,0}; int dy[4]={0,1,0,-1}; struct coder{ int x,y; }; coder fz(int x,int y){ coder a; a.x=x; a.y=y; return a; } bool pan(int x,int y){//判断走的这一步是否合法qwq return x>=1&&x<=n&&y>=1&&y<=m&&b[x][y]==0; } queue<coder> q; void bfs(){ q.push(fz(sx,sy)); while(!q.empty()){ coder h=q.front(); q.pop(); for(int i=0;i<4;i++){ int xx=h.x,yy=h.y; if(pan(h.x+dx[i],h.y+dy[i])){ xx+=dx[i]; yy+=dy[i]; b[xx][yy]=1; q.push(fz(xx,yy)); if(xx==fx&&yy==fy){ ans++; continue; } } } } } int main(){ scanf("%d%d%d",&n,&m,&t); scanf("%d%d",&sx,&sy); b[sx][sy]=1; scanf("%d%d",&fx,&fy); for(int i=1;i<=t;i++){ scanf("%d%d",&x,&y); b[x][y]=1; } bfs(); cout<<ans<<endl; }
会是这样的结果:
为什么嘞,因为你发现某个点走过以后就被标记为1了,这个点不能再走了(没有回溯啊喂)
拿以下测试点来讲qwq:
【输入样例】 【输出样例】
5 5 5 10
1 2 5 5
2 1
2 2
2 3
2 4
3 4
然而上面的程序输出是1,
why?
因为它标记首先是这样的:
接下来它开始走程序:
如果按楼上程序的话,当这个点到达终点时,终点被标记进来了欸??突然发现思维bug,显然bug很大qwq(虽然改掉bug也过不了的qwq)
因为就算改了过来,它还是被标记为走过,不管从哪一步开始走,都变为1惹qwq
所以也就少了好多好多种情况啊,所以显然不行,那我们就要想一想如何回溯一下嗯
前方高能预警qwq
在结构体coder里开一个神奇的gl(高璐)数组,用来标记走到某个x,y时map的样子,然后定义一个coder型队列q,每次取队首元素(包括这一个点的横纵坐标以及这个点的map)每次取出的map不一样,这样就可以保证对于回溯时,不会出现还没走就标记了的情况,然后在每次结尾的时候再把这个位置的map入队,等待下一次取出调用。
解释一下memcpy的用途:就是把h结构体中存的坐标为(h.x,h.y)或者讲为没有进行加法运算时的(xx,yy)的map传递给hyh.gl,然后把这个点的map标记为1(请注意这个点不能是终点),入队。
这样的话相当于用结构体h来操作,用结构体hyh来储存数据和入队
可不可以直接上代码qwq:
#include<iostream> #include<queue> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int n,m,t,sx,sy,fx,fy,x,y,ans; bool b[10][10]; int dx[4]={1,0,-1,0}; int dy[4]={0,1,0,-1}; struct coder{//定义一个结构体coder(我也不知道为什么要叫这个名字) int x,y;//结构体内包含横纵坐标 int gl[10][10];//和用来标记这个点是否走过的数组gl(我是不会告诉你我拿我初中同学的名字来命名变量的qwq) }; coder hyh;//定义一个coder型变量hyh(我是不会告诉你我拿我初中同学的名字来命名变量的qwq) queue<coder> q;//定义一个coder型队列q void bfs(){//广搜 hyh.x=sx;//把起点的横纵坐标赋给hyh.x,hyh.y; 起点标记为已访问 hyh.y=sy; hyh.gl[sx][sy]=1; q.push(hyh);//入队 while(!q.empty()){ coder h=q.front();//取出队首元素 q.pop();//把队首元素出队 for(int i=0;i<4;i++){ int xx=h.x,yy=h.y; xx+=dx[i]; yy+=dy[i]; if(xx>n||xx<1||yy>m||yy<1||b[xx][yy]||h.gl[xx][yy]){//判断不满足条件的情况(不满足就进行下一次循环) continue; } if(xx==fx&&yy==fy){//到终点,ans+1; ans++; continue; } hyh.x=xx;//没有到终点,把走一步后的元素给hyh(包括某一个位置走过否 hyh.y=yy; memcpy(hyh.gl,h.gl,sizeof(h.gl)); hyh.gl[xx][yy]=1;//把走到这个点标为1 q.push(hyh);//入队 } } } int main(){ scanf("%d%d%d",&n,&m,&t);//输入惹 scanf("%d%d",&sx,&sy); scanf("%d%d",&fx,&fy); for(int i=1;i<=t;i++){ scanf("%d%d",&x,&y); b[x][y]=1;//构造了一个矩阵,如同一个01地图,障碍物标记为1,通路标记为0; } bfs();//广搜代码,与dfs(大法师)相对 cout<<ans<<endl; }
end-