0
点赞
收藏
分享

微信扫一扫

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


                                        胜利大逃亡(续)

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


 

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

用一个二进制数表示当前这个点有哪几把钥匙,比如0011表示有1,2两把钥匙(a,b),如果当前这个点是门,则用&,比如0011&0010=0010说明当前这扇门能打开,能走。
如果当前这个点是钥匙,则用|,比如0011|1000=1011 说明到当前这个点找到了1,2,4这几把钥匙
1<<s[i][j]-'a',表示将1左移x位,对应第x把钥匙
 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <stack>
#define rson rt<<1|1
#define lson rt<<1
using namespace std ;
typedef long long LL;
const int MAX = 100 ;
char Map[MAX][MAX] ;
int vis[50][50][2000] ;
int sx ,sy ;
int ex ,ey ;
struct Point{
int x ;
int y ;
int k ;// 用来记录当前这个点能打开哪几扇门,即捡到了哪几把钥匙
int step ;
};

int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};
int n , m ,t ;
int bfs(Point start ,Point end )
{
queue<Point> Q ;
start.step = 0 ;
start.k = 0 ;
vis[start.x][start.y][start.k] = 1 ;
Q.push(start);
while(!Q.empty())
{
Point p = Q.front() ;
Q.pop() ;
if(Map[p.x][p.y]=='^')
{
if(p.step <t )
{
return p.step ;
}
else
{
return 0 ;
}
}
if(p.step>=t)
return 0 ;// 当前已经过时间了
for(int k = 0 ;k<4 ;k++)
{
int nextx = p.x + dx[k] ;
int nexty = p.y + dy[k] ;

if(nexty>=0 && nextx>=0 && nextx<n &&nexty<m && Map[nextx][nexty]!='*')
{
Point tmp ;
tmp.x = nextx ;
tmp.y = nexty ;
tmp.k = p.k ;
tmp.step = p.step+1 ;
if(Map[tmp.x][tmp.y] >='a'&& Map[tmp.x][tmp.y]<='z')
{
// 钥匙 ;
int key = p.k|(1<<(Map[tmp.x][tmp.y]-'a')) ;

if(!vis[tmp.x][tmp.y][tmp.k])
{
vis[tmp.x][tmp.y][tmp.k] = 1 ;
tmp.k = key ;
Q.push(tmp);

}

}
else if(Map[tmp.x][tmp.y] >='A'&& Map[tmp.x][tmp.y]<='Z')
{
// 如果下一个点是门;
int key = p.k&(1<<(Map[tmp.x][tmp.y]-'A'));

if(!vis[tmp.x][tmp.y][tmp.k] && key)
{
// 如果有打开改门的钥匙
vis[tmp.x][tmp.y][tmp.k] = 1 ;

Q.push(tmp);

}


}
else
{
// 路
if(!vis[tmp.x][tmp.y][tmp.k])
{
vis[tmp.x][tmp.y][tmp.k] = 1 ;
Q.push(tmp) ;

}

}

}

}
}

return 0;
}
int main()
{


while(~scanf("%d%d%d",&n,&m,&t)){
Point start ;
Point end ;
memset(vis,0,sizeof(vis)) ;
for(int i = 0 ; i<n ;i++)
{
scanf("%s",Map[i]);
for(int j = 0 ;j<m ;j++)
{
if(Map[i][j] =='@')
{
sx = i ;
sy = j ;
start.x = i ;
start.y = j ;
}
if(Map[i][j] == '^')
{
ex = i ;
ey = j ;
end.x = i ;
end.y = j ;
}

}
}

int ans = bfs(start,end) ;
if(ans)
{
printf("%d\n",ans);
}
else
{
printf("-1\n");
}


}

return 0 ;
}

 

 

举报

相关推荐

0 条评论