迷宫类汇总

洛谷 P1141 01迷宫

题目分析:看网上的大佬们都说这道题普通的搜索和广搜都过不去,得要优化一下,有些大佬使用hash判重和并查集?(我是没有懂,我还是太菜了)然后就继续翻别人的博客,后面发现了两种很优美的算法,一种是深搜,一种是广搜。分别贴出来吧,其实这两位的都用到了差不多一样的优化,这种优化挺好的。(不要问我为什么都是贴的别人的,因为考试快来了,没那多时间了,所以主要是学学思路)
深搜代码(来自洛谷用户:囧人232

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int dx[4]={-1,0,1,0};
const int dy[4]={0,1,0,-1};
int g[1001][1001],f[1001][1001],d[1000005];//d数组就是在下的优化,每种颜色对应的答案
int n,m,k,ans,cnt=1;
string c;
void init(){ans=0;}
void dfs(int x,int y){
    ans++; f[x][y]=cnt;
    for(int i=0;i<4;++i) {
        int xx=x+dx[i],yy=y+dy[i];
        if(!f[xx][yy]&&1<=xx&&xx<=n&&1<=yy&&yy<=m&&(g[xx][yy]!=g[x][y])) dfs(xx,yy);
    }
    d[cnt]=ans;
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        cin>>c; m=c.size();
        for(int j=0;j<m;j++) g[i][j+1]=c[j]-'0';
    }
    for(int i=1;i<=k;i++){
        init();
        int a,b;
        scanf("%d%d",&a,&b);
        if(!f[a][b]){ dfs(a,b); cnt++; }
        printf("%d\n",d[f[a][b]]);
    }
    return 0;
}

下面这种是广搜(Luogu P1141 01迷宫

#include <cstdio>
using namespace std;
struct node {
    int x,y,s;
}a[1000001];
char map[1001][1001];
int n,m,startx,starty,num,book[1001][1001],mark[1001][1001],ans[1000001]; 
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int bfs(int color){
    int head=1,tail=2,tx,ty,k,sum=1;
    mark[startx][starty]=color; book[startx][starty]=1;
    a[head].x=startx;a[head].y=starty; a[head].s=0;
    while(head<tail){
        for(k=0;k<=4-1;k++){
            tx=a[head].x+next[k][0]; ty=a[head].y+next[k][1];
            if(tx<1 || tx>n || ty<1 || ty>n) continue;
            if(map[tx][ty]!=map[a[head].x][a[head].y] && book[tx][ty]==0){
                book[tx][ty]=1; mark[tx][ty]=color;
                sum++;
                a[tail].x=tx; a[tail].y=ty;
                a[tail].s=a[head].s+1;
                tail++;
            }
        }
        head++;
    }
    return sum;
}
int main(){
    num=1;
    int i,j;
    scanf("%d %d\n",&n,&m);
    for(i=1;i<=n;i++){ gets(map[i]+1); }
    for(i=1;i<=m;i++) {
        scanf("%d %d",&startx,&starty);
        if(mark[startx][starty]!=0) {
            printf("%d\n",ans[mark[startx][starty]]);
        }
        else {
            ans[num]=bfs(num);
            printf("%d\n",ans[num]);
        }
        num++;
    }
    return 0;
}

不知为何当初的自己要发以上两篇博客,明明很简单的题目,发博客就算了,结果还是别人的,真是太菜了.

洛谷 P1363 幻想迷宫

题目描述

背景 Background

(喵星人LHX和WD同心协力击退了汪星人的入侵,不幸的是,汪星人撤退之前给它们制造了一片幻象迷宫。)

WD:呜呜,肿么办啊……

LHX:momo…我们一定能走出去的!

WD:嗯,+U+U!

描述 Description

幻象迷宫可以认为是无限大的,不过它由若干个N*M的矩阵重复组成。矩阵中有的地方是道路,用’.’表示;有的地方是墙,用’#’表示。LHX和WD所在的位置用’S’表示。也就是对于迷宫中的一个点(x,y),如果(x mod n,y mod m)是’.’或者’S’,那么这个地方是道路;如果(x mod n,y mod m)是’#’,那么这个地方是墙。LHX和WD可以向上下左右四个方向移动,当然不能移动到墙上。

请你告诉LHX和WD,它们能否走出幻象迷宫(如果它们能走到距离起点无限远处,就认为能走出去)。如果不能的话,LHX就只好启动城堡的毁灭程序了……当然不到万不得已,他不想这么做。。。
输入输出格式
输入格式:

输入格式 InputFormat

输入包含多组数据,以EOF结尾。

每组数据的第一行是两个整数N、M。

接下来是一个N*M的字符矩阵,表示迷宫里(0,0)到(n-1,m-1)这个矩阵单元。

输出格式:

输出格式 OutputFormat

对于每组数据,输出一个字符串,Yes或者No。

输入输出样例
输入样例#1

5 4
##.#
##S#
#..#
#.##
#..#
5 4
##.#
##S#
#..#
..#.
#.##

输出样例

Yes
No

说明

数据范围和注释 Hint

对于30%的数据,N,M<=20

对于50%的数据,N.M<=100.

对于100%的数据,N,M<=1500,每个测试点不超过10组数据.

题目分析

笼统的说,这道题就是要找一条路,可以无穷尽的走下去.也就是差不多走到某个点后,可以从这点回到原来的起点.可以看看这个大佬解释的:https://www.luogu.org/blog/GNAQ/solution-p1363

程序代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,sx,sy,dx[4]={0,-1,0,1},dy[4]={-1,0,1,0},ans=0;
int vis[1510][1510][3]={0};
bool map[1510][1510]={false};
void dfs(int x,int y,int xx,int yy) {
    if(vis[xx][yy][2]&&(vis[xx][yy][0]!=x||vis[xx][yy][1]!=y)) {ans=1;return ;}//如果这个点走过,并且不完全是和上一个点相同,那就返回1
    if(vis[xx][yy][2]&&vis[xx][yy][0]==x&&vis[xx][yy][1]==y) return ;//如果走到上一个点,那就回溯
    vis[xx][yy][0]=x;vis[xx][yy][1]=y;vis[xx][yy][2]=1;//记录一下
    register int x1,y1;
    for(register int w=0;w<=3;++w){
        x1=(xx+dx[w]+n)%n;y1=(yy+dy[w]+m)%m;
        if(map[x1][y1]) dfs(x+dx[w],y+dy[w],x1,y1);
    }
}
int main(){
    char ch;
    while(cin>>n>>m) {
        memset(map,false,sizeof(map));
        memset(vis,false,sizeof(vis));
        ans=0;
        for(register int i=0;i<n;++i)
            for(register int j=0;j<m;++j){
                cin>>ch;
                if(ch=='.') map[i][j]=true;
                else if(ch=='S') {  sx=i;sy=j;map[i][j]=true;}
            }
        dfs(sx,sy,sx,sy);
        if(ans) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值