(poj 2157 Maze)<搜索>

传送门

Solution

“如果走投无路,试试打开一扇门,或许能绝处逢生”
所以思路就是当队列为空时,把所有曾经经过且找到全部对应钥匙的门加入队列(从wait数组里找),注意是所有的,而且入队后不能将其从wait数组中移出。而经过一扇门时,无论是否找到所有对应钥匙,都不入队,只将其加入wait数组。
为什么呢?因为路是可以重复走的,所以我们并不知道曾经哪扇门可以到达终点,这次从wait数组入队但未能到达终点并不意味着下次也不可以,也就是说,wait数组会越来越长。
另外有一点,如果真的“走投无路”,那么就会死循环,因为队列会一遍遍清空,而wait数组不会缩短,就只能一遍遍加入队列,永远跑不出来。
于是我机智(zei)地假设它如果不是“走投无路”的话,wait数组加入队列的次数不会超过15次。如果超过,就判断为无法到达
至于15是怎么来的,嗯猜的,也许数据水吧

Code

// by spli
#include<cstring>
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;

int n,m;
char s[25][25];
int num[10];
struct node{
    int x,y;
};
queue<node>q;//队列
int wx[100],wy[100];//wait数组
int head;
int tim;//加入次数
bool vis[25][25];//记录是否入队
bool can[25][25];//记录是否加入wait数组
int dx[5]={0,1,0,-1,0};
int dy[5]={0,0,1,0,-1};
int ax,ay;

void bfs(){
    node f;
    int x,y,kx,ky;
    while(!q.empty()){
        f=q.front();
        q.pop();
        x=f.x;y=f.y;
        for(int i=1;i<=4;++i){
            kx=x+dx[i];
            ky=y+dy[i];
            if(s[kx][ky]>='A'&&s[kx][ky]<='E'){
                if(can[kx][ky]) continue;
                can[kx][ky]=1;
                wx[head]=kx;
                wy[head++]=ky;
            }
            else if(kx>=1&&kx<=n&&ky>=1&&ky<=m&&!vis[kx][ky]&&s[kx][ky]!='X'){
                    vis[kx][ky]=1;
                    q.push((node){kx,ky});
                    if(s[kx][ky]>='a'&&s[kx][ky]<='e')
                        num[s[kx][ky]-'a']--;
                }
        }
        if(vis[ax][ay]) return;
        if(q.empty()&&tim<15){  //骗分哈哈哈 
            ++tim;
            for(int j=0;j<head;++j){    //全部入队 
                x=wx[j],y=wy[j];
                //if(!(x+y)) continue;
                if(!num[s[x][y]-'A']) q.push((node){x,y});
                //wx[j]=wy[j]=0;不能移出wait数组
            }
        }
    }
}

int main(){
    while(scanf("%d%d",&n,&m)&&n&&m){
        for(int i=0;i<10;++i) num[i]=0;
        tim=head=0;
        while(!q.empty()) q.pop();
        for(int i=1;i<=n;++i){
            scanf("%s",s[i]+1);
            for(int j=1;j<=m;++j){
                vis[i][j]=can[i][j]=0;
                if(s[i][j]=='S') q.push((node){i,j}),vis[i][j]=1;
                if(s[i][j]>='a'&&s[i][j]<='e') num[s[i][j]-'a']++;
                if(s[i][j]=='G') ax=i,ay=j;
            }
        }
        bfs();
        if(vis[ax][ay]) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

//以下是poj讨论区的几组数据
/*
7 5
S..AG
c...X
XXCXX
b....
XXXBX
a....
XXXXX
*/


/*
4 4 
S.X. 
a.X. 
..XG 
.... 
3 4 
S.Xa 
.aXB 
b.AG 
0 0
*/


/*
11 6
X.XXE.
X.GXX.
.D.dXS
...X..
.X.Xac
..XXaX
X..X.X
X..a.B
XA..Cc
.XX..X
...X.X
6 8
S......D
X.X.X.X.
XeX.X.Xc
bA..XeXB
XXX.XbXE
aCd.XaXG
5 7
S.....D
XX.X.Xc
bA.XeXB
XX.XbXE
aCdXaXG
11 6
X.XXE.
X.GXX.
.D.dXS
...X..
.X.Xac
..XXaX
X..X.X
X..a.B
XA..Cc
.XX..X
...X.X
12 13
S............
aXXXXXAXXXXX.
bXXXXXbXXXXX.
cXXXXXeXXXXX.
dXXXXXXXXXXX.
eXXXXXXXXXXX.
.BcXXG.Xe....
.XXXXX.XXXXX.
.XXXXX.XXXXX.
.CdDeX.....E.
.XXXXXXXXXXX.
.............
20 20
....................
.XXXXXXXXXXAXXXXXXX.
.X................X.
.X.XXXXXXXXXXXXXX.X.
.X.X............X.X.
.X.X.XXXXXXXXXX.X.X.
.X.X.XcX......X.X.X.
.X.X.X.XDXXXX.X.X.X.
.X.X.X.X.XXXX.X.X.X.
.X.X.X.X.E.GX.X.X.X.
aX.X.X.X.XXXX.C.X.X.
.X.X.X.X...eX.X.X.X.
.X.X.X.XXXXXXdX.X.X.
.X.X.X......dXX.X.X.
.X.X.XXXXX.XXXX.X.X.
.X.X............X.X.
.X.XXXXXXXBXXXXXX.X.
.X...............bX.
.XXXXXXXXXXXXXXXXXX.
.................S..
0 0
*/


/*
20 20
S..................a
aXXXXXXXXXXAXXXXXXX.
.X........bb......X.
.XbXXXXXXXXXXXXXX.X.
.X.X.....c......X.X.
aXbX.XXXXXXXXXX.X.X.
.X.X.X........X.X.X.
.X.X.X.XDXXXX.X.X.X.
.X.X.X.X..XXX.X.X.X.
.X.X.X.X.XG.X.X.X.X.
.X.XcX.X.XXEX.CeX.X.
.X.X.X.X.e..X.X.X.X.
.X.X.X.XXXXXX.X.X.X.
.X.X.X........X.X.X.
.X.X.XXXXXXXXXX.X.X.
.X.X..c.........X.X.
.X.XXXXXXXBXXXXXX.X.
.X........b.......X.
.XXXXXXXXXXXXXXXXXX.
.d..e...a........a..
*/




/*
20 20
S...................
.XXXXXXXXXXAXXXXXXX.
.X...........a....X.
.X.XXXXXXXXXXXXXX.X.
.X.X............X.X.
.X.X.XXXXXXXXXX.X.X.
.X.X.X........X.X.X.
.X.X.X.XDXXXX.X.X.X.
.X.X.X.X..XXX.X.X.X.
.X.X.X.X.XG.X.X.X.X.
.X.X.X.X.XXEX.C.X.X.
.X.X.X.X....X.X.X.X.
.X.X.X.XXXXXX.X.X.X.
.X.X.X........X.X.X.
.X.X.XXXXXXXXXX.X.X.
.X.X............X.X.
.X.XXXXXXXBXXXXXX.X.
.X................X.
.XXXXXXXXXXXXXXXXXX.
....................
*/


/*
4 5
S..AG
.XX.X
BX...
aX.Xb
0 0
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值