HDU1429 胜利大逃亡(续)(状态压缩+广搜BFS )

题目:

胜利大逃亡(续)

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8573    Accepted Submission(s): 3076


Problem Description
Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)……

这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了带锁的门,钥匙藏在地牢另外的某些地方。刚开始Ignatius被关在(sx,sy)的位置,离开地牢的门在(ex,ey)的位置。Ignatius每分钟只能从一个坐标走到相邻四个坐标中的其中一个。魔王每t分钟回地牢视察一次,若发现Ignatius不在原位置便把他拎回去。经过若干次的尝试,Ignatius已画出整个地牢的地图。现在请你帮他计算能否再次成功逃亡。只要在魔王下次视察之前走到出口就算离开地牢,如果魔王回来的时候刚好走到出口或还未到出口都算逃亡失败。
 

Input
每组测试数据的第一行有三个整数n,m,t(2<=n,m<=20,t>0)。接下来的n行m列为地牢的地图,其中包括:

. 代表路
* 代表墙
@ 代表Ignatius的起始位置
^ 代表地牢的出口
A-J 代表带锁的门,对应的钥匙分别为a-j
a-j 代表钥匙,对应的门分别为A-J

每组测试数据之间有一个空行。
 

Output
针对每组测试数据,如果可以成功逃亡,请输出需要多少分钟才能离开,如果不能则输出-1。
 

Sample Input
 
   
4 5 17 @A.B. a*.*. *..*^ c..b* 4 5 16 @A.B. a*.*. *..*^ c..b*
 

Sample Output
 
   
16 -1
 

Author
LL
 

Source
ACM暑期集训队练习赛(三)
 

Recommend
linle   |   We have carefully selected several similar problems for you:   1254  1026  1728  1401  1372 
 

Statistic |  Submit |  Discuss |  Note
思路:

既然是状态压缩,那就在这里说一下状态压缩:

题上有A~J个门,有a~j个钥匙,还有终点,我们用二进制的方式来标记。

从a~j一共有十位,那我们就需要十个二进制位。

标    记:a  b  c  d  e  f   g  h  i   j  

第几位:0  0  0  0  0  0  0  0  0  0  

位编号:1  2  3  4  5  6  7  8  9  10

我们通过改变每一位的0和1来标记我当前拥有的钥匙的可能,也就是状态压缩,用vis[x][y][key]来表示当前在x,y点的状态。当遇到铁门时,先用|运算判断key的值1<<(map[x][y]-'A')的值和原来的key值是否一样,如果一样就代表当前有钥匙可以打开这个门,可以继续走,反之不能走这个门,因为没有钥匙。

如果遇到钥匙的话就更新key的值,然后在把当前状态标记为1,进行正常的广搜就可以,具体看注释

(关于位运算可以看一下搜狗百科的关键字:位运算)

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 10000007
#define debug() puts("what the fuck!!!")
#define N 1001000
#define M 1000000
#define ll long long
using namespace std;
int n,m,ans,t,sx,sy,ex,ey;
char map[25][25];
int vis[25][25][(1<<10)+20];//用二进制位来记录状态
int go[4][2]= {0,1,0,-1,1,0,-1,0};
struct node
{
    int x,y,step;
    int key;
};
int bfs(int x,int y)
{
    node now,to;
    now.x=x,now.y=y,now.step=0,now.key=0;
    vis[x][y][0]=1;
    queueq;
    q.push(now);
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        if(now.x==ex&&now.y==ey&&now.step=0&&to.x=0&&to.y='A'&&map[to.x][to.y]<='J')
                {
                    int key=to.key|(1<<(map[to.x][to.y]-'A'));//看看会不会对应位置的二进制数造成影响,从而判断有没有打开这扇门的钥匙
                    if(key!=to.key)//造成影响证明没有钥匙,直接进行下一层循环
                        continue;
                }
                if(map[to.x][to.y]>='a'&&map[to.x][to.y]<='j')
                {
                    to.key=to.key|(1<<(map[to.x][to.y]-'a'));//把当前的钥匙吸收进去
                }
                vis[to.x][to.y][to.key]=1;
                q.push(to);
            }
        }
    }
    return -1;
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&t))
    {
        mem(map,0);
        mem(vis,0);
        for(int i=0; i


你可能感兴趣的:(【搜索(DFS/BFS)】)