【洛谷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-

posted @ 2019-04-15 20:05  Sweetness  阅读(360)  评论(0编辑  收藏  举报