Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^
题目描述
话说CZ由于不守基道,被妖怪抓走了,好基友WP在努力讨好高富帅RQ救出CZ的同时,CZ也意识到了自己的错误,然后努力的想逃出妖怪的闺房。
妖怪的闺房是一个n*m的矩阵,并且某些地方安装了带锁的门,钥匙藏在闺房另外的某些地方。刚开始WP被关在(sx,sy)的位置,离开闺房的门在(ex,ey)的位置。WP每分钟只能从一个坐标走到相邻四个坐标中的其中一个。妖怪每t分钟回闺房视察一次,若发现CZ不在原位置便把他再拎回去。经过若干次的尝试,CZ已画出整个闺房的地图。现在请你帮他计算能否再次成功逃亡。只要在妖怪下次视察之前走到出口就算离开闺房,如果妖怪回来的时候刚好走到出口或还未到出口都算逃亡失败。
输入
每组测试数据的第一行有三个整数n,m,t(2<=n,m<=20,t>0)。接下来的n行m列为闺房的地图,其中包括
:
. 代表路
* 代表墙
@ 代表CZ的起始位置
^ 代表闺房的出口
A-J 代表带锁的门,对应的钥匙分别为a-j
a-j 代表钥匙,对应的门分别为A-J
. 代表路
* 代表墙
@ 代表CZ的起始位置
^ 代表闺房的出口
A-J 代表带锁的门,对应的钥匙分别为a-j
a-j 代表钥匙,对应的门分别为A-J
每组测试数据之间有一个空行。
输出
针对每组测试数据,如果可以成功逃亡,请输出最少需要多少分钟才能离开,如果不能则输出-1。
示例输入
4 5 17
@A.B.
a*.*.
*..*^
c..b*
4 5 16
@A.B.
a*.*.
*..*^
c..b*
示例输出
16
-1
这个题很麻烦,但是思路很巧妙,不能用哈希来记录是否拿到了钥匙,而是用二进制的01来记录...
思路:用bfs搜索,不过标记变量需要注意一些问题。首先找到‘@’(起点),然后搜,遇到门判钥匙是否存在,存在的话放到队列里,不存在不放,遇到钥匙判是否存在,存在的话就不必收起来了,不存在的话就收起来。这里钥匙是不能单独存储的,因为你拿到钥匙后,有些以前不能去的地方你能去了,如第一组数据:你先搜到的是a,然后是A,你在搜到A判断是否有A的时候,就会是有,然后就会把A这个点的坐标放到队列里,这样就错了,因为你要先到a这个点,然后再回去遇到A才能把A放到队列里,再一个问题是就算是你走到a了,但是,二维数组已经标记过‘@’,因此,不会往回搜索了,所以,此题需要用一个三维标记数组来写。
二进制表示状态的办法:
如1,变成二进制是1,那么就代表A有相应的钥匙(a),如果是100(二进制),则代表有C的钥匙(c),怎么判断呢?用位运算,当然,你用二进制和十进制互换的那个算法也对。。。这里说二进制。。。判C的钥匙是否存在:
<span style="font-size:18px;">int a = 4;
int zh = 'C' - 'A';
int b = ((a >> zh) & 1);</span>
>> 是右移运算符,100(二进制)右移两位就是1,&是位与,真值情况和逻辑中的且是一样的,很明显,这里是1,也就是说b为1,(不会的学学位运算)。。。。。
把钥匙加入也要用到二进制位运算,还要用到位或(|),比如一开始什么钥匙都没有,突然遇到了d,然后加入就是:
int a = 0;
int zh = 'd' - 'a';
int b = ((1 << zh) | a);
1左移两位是1000(二进制,左移中没有的补0,比如110(二进制),左移一位就是1100(二进制)),然后取位或(|), 真值情况和逻辑中的或是一样的,很明显,这里是b用二进制是1000,换成十进制是8。
#include <stdio.h>
#include <ctype.h>
#include <string.h>
bool vis[1025][21][21];//这个数组是bfs的标记数组,多余的一维时用来记录是否含有某一把钥匙的
char mp[21][21];//地图记录
struct node
{
int x;
int y;
int ans;
int z;
}ls[8000010];//bfs中的队列
int bhx[] = {0,0,1,-1};
int bhy[] = {1,-1,0,0};//四个方向
bool pdys(int x,char c)//判断某个钥匙是否存在,第一个参数是目前存储钥匙是否存在的那个数的值,第二个参数就是判断这个门的钥匙是否存在
{
int zh = c - 'A';
return bool((x >> zh) & 1);
}
bool pdcz(int x,char c)//判断钥匙是否存在,这里是遇见了钥匙,上面是遇见了门
{
int zh = c - 'a';
return bool((x >> zh) & 1);
}
int sqys(int x,char c)//把钥匙收到手中,也就是变化存储钥匙的那个数
{
int zh = c - 'a';
return ((1 << zh) | x);
}
void bfs(int x,int y,int n,int m,int step)
{
memset(vis,false,sizeof(vis));
int tp = 0,tl = 0;
node t,f;
t.x = x;
t.y = y;
t.ans = 0;
t.z = 0;
ls[tp++] = t;
vis[t.z][t.x][t.y] = true;
while(tl < tp)
{
t = ls[tl++];
if(mp[t.x][t.y] == '^')
{
if(t.ans < step)
printf("%d\n",t.ans);
else
printf("-1\n");
return ;
}
for(int i = 0;i < 4;i++)
{
f.x = t.x + bhx[i];
f.y = t.y + bhy[i];
f.z = t.z;
f.ans = t.ans + 1;
if(f.x >= 0 && f.x < n && f.y >= 0 && f.y < m \
&& !vis[f.z][f.x][f.y] && mp[f.x][f.y] != '*')
{
if(isupper(mp[f.x][f.y]))
{
if(pdys(f.z,mp[f.x][f.y]))
{
ls[tp++] = f;
vis[f.z][f.x][f.y] = true;
}
}
else if(islower(mp[f.x][f.y]))
{
if(!pdcz(f.z,mp[f.x][f.y]))
{
f.z = sqys(f.z,mp[f.x][f.y]);
ls[tp++] = f;
vis[f.z][f.x][f.y] = true;
}
else
{
ls[tp++] = f;
vis[t.z][f.x][f.y] = true;
}
}
else
{
ls[tp++] = f;
vis[f.z][f.x][f.y] = true;
}
}
}
}
printf("-1\n");//以前这里没加 总是错,后来问了问人家才知道,原来还有没有出口的情况,你说人家救个基友容易么????
}
int
main()
{
int n,m,step;
while(~scanf("%d%d%d",&n,&m,&step))
{
for(int i = 0;i < n;i++)
{
scanf("%s",mp[i]);
}
for(int i = 0;i < n;i++)
{
int j;
for(j = 0;j < m;j++)
{
if(mp[i][j] == '@')
{
bfs(i,j,n,m,step);
break;
}
}
if(j < m)
break;
}
}
return 0;
}