hdu 1885 Key Task【状压搜索】

Key Task

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1824    Accepted Submission(s): 772


Problem Description
The Czech Technical University is rather old — you already know that it celebrates 300 years of its existence in 2007. Some of the university buildings are old as well. And the navigation in old buildings can sometimes be a little bit tricky, because of strange long corridors that fork and join at absolutely unexpected places. 

The result is that some first-graders have often di?culties finding the right way to their classes. Therefore, the Student Union has developed a computer game to help the students to practice their orientation skills. The goal of the game is to find the way out of a labyrinth. Your task is to write a verification software that solves this game. 

The labyrinth is a 2-dimensional grid of squares, each square is either free or filled with a wall. Some of the free squares may contain doors or keys. There are four di?erent types of keys and doors: blue, yellow, red, and green. Each key can open only doors of the same color. 

You can move between adjacent free squares vertically or horizontally, diagonal movement is not allowed. You may not go across walls and you cannot leave the labyrinth area. If a square contains a door, you may go there only if you have stepped on a square with an appropriate key before.
 

Input
The input consists of several maps. Each map begins with a line containing two integer numbers R and C (1 ≤ R, C ≤ 100) specifying the map size. Then there are R lines each containing C characters. Each character is one of the following: 



Note that it is allowed to have 
  • more than one exit,
  • no exit at all,
  • more doors and/or keys of the same color, and
  • keys without corresponding doors and vice versa.

    You may assume that the marker of your position (“*”) will appear exactly once in every map. 

    There is one blank line after each map. The input is terminated by two zeros in place of the map size.
 

Output
For each map, print one line containing the sentence “Escape possible in S steps.”, where S is the smallest possible number of step to reach any of the exits. If no exit can be reached, output the string “The poor student is trapped!” instead. 

One step is defined as a movement between two adjacent cells. Grabbing a key or unlocking a door does not count as a step.
 Sample Input
1 10
*........X


1 3
*#X


3 20
####################
#XY.gBr.*.Rb.G.GG.y#
####################


0 0
 


Sample Output
Escape possible in 9 steps.
The poor student is trapped!
Escape possible in 45 steps.

题目大意,你在一个n*m的迷宫里边,*代表你的起点,X代表终点,小写字母代表钥匙,能够开对应大写字母的门,问最小步数。

分析:因为有多把钥匙,我们直接枚举各种情况比较复杂,(虽然这个题只有四把钥匙直接枚举所有情况也可以,但是如果26把呢?所以还是用状压吧~)所以我们考虑状态压缩+BFS的解法。


解题过程:

我们设置一个01串表示对于这种钥匙的有无,对于四把钥匙,我们设置长为4的01串,对于其中含义,1表示有这种钥匙,0表示没有这种钥匙,举例说明:

0001表示有第一把钥匙,0101表示有第三把和第一把钥匙。因为存01串比较麻烦,所以状压的过程也是把01串变成10进制值的过程。

对于状态压缩的初始化我们搞定了,之后就要讨论钥匙的拿取和能否通过门的判断:

1、对于钥匙的拿取,如果遇到小写字母(也就是走到了钥匙所在的格子),我们要怎样在状态上修改呢?因为二进制值的计算法则,其实我们直接加上(1<<第几把钥匙)即可。假如现在01串的值为5:0101,现在走到了第四把钥匙所在的格子,这个时候状态改变为:5+(1<<4)=13即可。这个时候不妨算一下13的二进制数来证明:1101.结论成立。

2、对于门的打开,如果遇到了大写字母(也就是走到了门所在的格子),我们要怎样判断有没有这种门对应的钥匙呢?假设我们现在的状态值为13,对应01串为:1101,这个时候我们遇到了第四个门,我们看01串是完全可以看出来是确实有第四个门的钥匙的,而且我们也可以把十进制的数转成二进制数然后来判断,但是那样太麻烦了,我们只需要用1101&1000即可,因为与运算的特殊性,只有两个1的时候才能出 1,其他情况全出0,那么我们用这个特性就可以直接来判断我们需要的第几把钥匙的有无,也就是:

当前状态值&(1<<第几个门),如果与值为0表示没有这个门对应的钥匙,否则表示有这个门对应的钥匙、

注意的点:

1、不要重复拿有过的钥匙,如果在这里没有判断的话,测测这组数据就知道会wa了~:

5 5
*rrGX
rrrrG
rrrrr
GrrrG
XGrGX
2、对于位运算的优先级规则记得不是很清楚的小伙伴门一定要在位运算的过程中都加上括号保证数据结果的正确。

3、枚举情况一定要全面。

AC代码:

#include<stdio.h>
#include<queue>
#include<string.h>
#include<math.h>
#include<iostream>
using namespace std;//duo ba yaoshi de qingkuang mei chuli
struct zuobiao
{
    int x,y,output,tmp;
} now,nex;
char a[115][115];
int vis[115][115][1<<5];
int fx[4]= {0,0,1,-1};
int fy[4]= {1,-1,0,0};
char men[4]= {'B','Y','R','G'};
char key[4]= {'b','y','r','g'};
int n,m;
void bfs(int x,int y)
{
    memset(vis,0,sizeof(vis));
    now.x=x;
    now.y=y;
    now.tmp=now.output=0;
    queue<zuobiao >s;
    vis[x][y][0]=1;
    s.push(now);
    while(!s.empty())
    {
        now=s.front();
        s.pop();
        if(a[now.x][now.y]=='X')
        {
            printf("Escape possible in %d steps.\n",now.output);
            return ;
        }
        for(int i=0; i<4; i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            nex.output=now.output+1;
            nex.tmp=now.tmp;
            if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&a[nex.x][nex.y]!='#')
            {
                if(isupper(a[nex.x][nex.y])&&a[nex.x][nex.y]!='X')
                {
                    for(int j=0; j<4; j++)
                    {
                        if(a[nex.x][nex.y]==men[j])
                        {
                            if((nex.tmp&(1<<j)))
                            {
                                if(vis[nex.x][nex.y][nex.tmp]==0)
                                {
                                    vis[nex.x][nex.y][nex.tmp]=1;
                                    s.push(nex);
                                }
                                break;
                            }
                        }
                    }
                }
                else if(islower(a[nex.x][nex.y]))
                {
                    for(int j=0; j<4; j++)
                    {
                        if(a[nex.x][nex.y]==key[j])
                        {
                            if((nex.tmp&(1<<j))==0)
                            {
                                nex.tmp+=(1<<j);
                            }
                            if(!vis[nex.x][nex.y][nex.tmp])
                            {
                                vis[nex.x][nex.y][nex.tmp]=1;
                                s.push(nex);
                            }
                        }
                    }
                }
                else
                {
                    if(vis[nex.x][nex.y][nex.tmp]==0)
                    {
                        vis[nex.x][nex.y][nex.tmp]=1;
                        s.push(nex);
                    }
                }
            }
        }
    }
    printf("The poor student is trapped!\n");
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)break;
        int sx,sy;
        for(int i=0; i<n; i++)
        {
            scanf("%s",a[i]);
            for(int j=0; j<m; j++)
            {
                if(a[i][j]=='*')
                {
                    sx=i;
                    sy=j;
                }
            }
        }
        bfs(sx,sy);
    }
}













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值