胜利大逃亡(续)(bfs+状态压缩)

胜利大逃亡(续)

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 85 Accepted Submission(s): 55
 
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
 
/*
题意:略

初步思路:这个题想了很久,钥匙的问题的没有办法解决,看了一下题解,才知道,搜索的状态在加一维就是压缩后的钥匙的状态,
    因为钥匙的数量不是很多,所以可以状态压缩一下来表示。
*/
#include<bits/stdc++.h>
using namespace std;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
bool vis[22][22][(1<<11)];//用来标记走到i,j这个并且钥匙压缩完之后的状态是k的状态
char mapn[22][22];//地图
int sx,sy;//初始位置
int n,m,t;
struct node{
    int x,y,step,state;
    node(){}
    node(int a,int b,int c,int d){
        x=a;
        y=b;
        step=c;
        state=d;
    }
};
bool ok(int x,int y){//坐标状态是不是合法
    if(x<0||x>=n||y<0||y>=m||mapn[x][y]=='*') return false;
    return true;
}
bool judge(int x,int y,int state){//判断一下这种状态是不是能通过这扇门
    int res=mapn[x][y]-'A';
    if(((1<<res)&state)==0) return false;
    return true;
}
int bfs(){
    memset(vis,0,sizeof vis);
    node Next,start;
    queue<node>q;
    q.push(node(sx,sy,0,0));
    vis[sx][sy][0]=1;
    while(!q.empty()){
        start=q.front();
        q.pop();
        // cout<<start.x<<" "<<start.y<<" "<<start.state<<endl;
        if(start.step>=t){
            return -1;
        }
        if(mapn[start.x][start.y]=='^'){
            return start.step;
        }
        for(int i=0;i<4;i++){
            Next=start;
            Next.x+=dir[i][0];
            Next.y+=dir[i][1];
            Next.step++;//走了一步了
            if(ok(Next.x,Next.y)==false)//出界了
                continue;
            if(mapn[Next.x][Next.y]>='A'&&mapn[Next.x][Next.y]<='Z'&&judge(Next.x,Next.y,Next.state)==false){//遇到门没有钥匙
                // cout<<Next.x<<" "<<Next.y<<" "<<Next.state<<endl;
                continue;
            }
            if(mapn[Next.x][Next.y]>='a'&&mapn[Next.x][Next.y]<='z'){//遇到钥匙
                int res=mapn[Next.x][Next.y]-'a';
                // cout<<"钥   匙="<<res<<endl;
                // cout<<"状   态="<<Next.state<<endl;
                Next.state=((1<<res)|Next.state);
                // cout<<"事后状态="<<Next.state<<endl;
            }
            if(vis[Next.x][Next.y][Next.state]==1)//这个状态走过了
                continue;
            vis[Next.x][Next.y][Next.state]=1;
            q.push(Next);
        }
    }    
    return -1;
}
int main(){
    // freopen("in.txt","r",stdin);
    while(scanf("%d%d%d",&n,&m,&t)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%s",&mapn[i]);
            for(int j=0;j<m;j++){
                if(mapn[i][j]=='@')
                    sx=i,sy=j;
            }
        }
        printf("%d\n",bfs());
    }
    return 0;
}

 

posted @ 2017-02-22 13:10  勿忘初心0924  阅读(561)  评论(0编辑  收藏  举报