2016.10.13模拟赛T1

A 迷宫(maze2.pas/c/cpp)
TL:1S ML:128MB
【Description】
你所在的迷宫可以用 N 行 M 列的矩阵来描述:
图标 含义
‘# ’ 墙,无法通过
. 地面,可以通过
小写字母(a、b、c、…、z) 钥匙,可以打开标有对应大写字母的门
大写字母(A、B、C、…、Z) 门,可以被标有对应小写字母的钥匙打开
shift+4 你的初始位置
& 迷宫的出口位置
迷宫的四周都有墙,所以你无法走出这片 N*M 的区域,只能从”&”处离开迷宫,你只能
向东西南北四个方向走。
你的任务是,计算出走出迷宫需要的最少步数是多少?
【Input】
第 1 行两个正整数 N 和 M,表示迷宫的长和宽;
第 2 行一个正整数 P,表示门和钥匙的数量;
第 3 行至第 N+2 行,描述整个迷宫。
【Output】
一个整数,为走出迷宫需要的最少步数或-1(如果不可能走出迷宫)。
【Sample Input】
5 5
1
&A..shift+4
####.
…#.
.#.#.
a#…
【Sample Output】
28
【Sample Input】
1 4
1
&aAshift+4
【Sample Output】
-1
【Hint】
对于 30%:1 <= N, M <= 15
另外存在 10%:P=0
另外存在 10%:P=1
另外存在 20%:P=2
对于 100%:1<=N,M<=50,0<=P<=10,保证迷宫中”$”、”&”和所有大小写字
母只出现一次,钥匙和门的标号只会出现字母表中的前 P 个字母。

mdzz…..昨天刚做了毒药解药,这个题没看出来是二进制状压。
这个地图上有钥匙和门,所以可能出现的情况是:有些门把终点挡住了。所以用普通迷宫的判重方法是不行的,我们需要这样:bool vis[maxn][maxn][1<<11];
第一二维表示横纵坐标,第三维表示是个二进制数,如01010011之类的,0代表当前没有拿到某个门的钥匙,1代表拿到。

这样的话,搜到钥匙就可以往回走了…

#include<cstdio>
#include<queue>
using namespace std;
int n,m,p;
const int maxn=60;
int sx,sy;
int ex,ey;
struct meico
{
    int x;
    int y;
    int key;
    int d;
};
queue<meico>q;
int x1[]={0,1,0,-1,0};
int y1[]={0,0,1,0,-1};
int map[maxn][maxn];
bool vis[maxn][maxn][1<<11];
char hah[maxn];
int key[maxn][maxn];
int door[maxn][maxn];
bool flag;
bool pd(int x,int y,int k)
{
    if(x>=1&&x<=n&&y>=1&&y<=m&&!vis[x][y][k])
    return true;
    return false;
}
void bfs()
{
    while(!q.empty())
    {
        for(int i=1;i<=4;i++)
        {
            int x=q.front().x;
            int y=q.front().y;
            int k=q.front().key;
            int d=q.front().d;
            x+=x1[i];
            y+=y1[i];
            if(map[x][y])
            {
                if(x==ex&&y==ey)
                {
                    printf("%d",d+1);
                    flag=1;
                    return;
                }

                if(key[x][y])
                {
                    k|=(1<<key[x][y]);
                    if(!vis[x][y][k])
                    {
                        vis[x][y][k]=1;
                        q.push((meico){x,y,k,d+1});
                    }
                    continue;           
                }
                else if(door[x][y])
                {
                    if((k>>door[x][y]&1))
                    {
                        if(!vis[x][y][k])
                        {
                            vis[x][y][k]=1;
                            q.push((meico){x,y,k,d+1});
                        }
                    }
                    continue;
                }
                else
                {
                    if(pd(x,y,k))
                    {
                        vis[x][y][k]=1;
                        q.push((meico){x,y,k,d+1});
                    }   
                }
            }
        }
        q.pop();
    }
}
int main()
{
    freopen("maze2.in","r",stdin);
    freopen("maze2.out","w",stdout);
    scanf("%d%d%d\n",&n,&m,&p);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",hah);
        for(int j=0;j<=m;j++)
        {
            map[i][j+1]=1;
            if(hah[j]=='#')
                map[i][j+1]=0;
            else if(hah[j]>='a'&&hah[j]<='z')
                key[i][j+1]=hah[j]-'a'+1;
            else if(hah[j]>='A'&&hah[j]<='Z')
                door[i][j+1]=hah[j]-'A'+1;
            else if(hah[j]=='$')
                sx=i,sy=j+1;
            else if(hah[j]=='&')
                ex=i,ey=j+1;
        }
    }
    q.push((meico){sx,sy,0,0});
    bfs();
    if(!flag)
        puts("-1");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值