胜利大逃亡
escape.pas/c/cpp
1S/256MB
【题目描述】
elfness被魔王抓走了,这次魔王把elfness关在一个n*m的地牢里。地牢的某个地方安装了一个带锁的门,钥匙藏在地牢的另外一个地方,elfness想要通过这个门,就必须先走到藏钥匙的地方取钥匙。刚开始的时候elfness被关在(sx,sy)的位置,而离开地牢的门在(ex,ey)的位置。elfness每分钟只能从一个位置走到相邻四个位置中的其中一个。魔王每t分钟都回地牢视察一次,若发现elfness不在原位置便会把他拎回去。经过若干次的尝试,elfness已经画出了整个地牢的地图。现在请你帮他计算能否再次成功逃亡。只要在魔王下次视察之前走到出口就算离开地牢,如果魔王回来的时候还未到出口都算逃亡失败。
【输入】
输入文件:escape.in
第一行有三个整数n,m,t。接下来的n行m列为地牢的地图,其中包括:
. 代表路
* 代表墙
@ 代表elfness的起始位置
^ 代表地牢的出口
A 代表带锁的门
a 代表钥匙
【输出】
输出文件:escape.out
输出为一行,包含一个整数。对于可以成功逃亡的情况,请输出至少需要多少分钟才能离开,如果不能则输出-1。
【输入样例】
4 4 100 @..A a.*. ***. ^...
【输出样例】
11
【数据范围】
对于100%的数据,2<=n,m<=20,t>0
这一题给人的第一印象就是和走迷宫如出一辙,然后深搜!
但是我们看看时间复杂度,极限情况一共有20*20=400个格子,而深搜的效率是O(2n),所以肯定超时了!!!
所以这个时候我们就应该选择宽搜的方法
对比走迷宫,我们这道题多了一个钥匙的状态,这个简单,一个key变量就可以记录下来!
走迷宫时为了提高搜索效率,我们在入队的时候会进行判重,如果当前点已经走过了,就不会再走了
但是这一题会出现这样一种情况,如下图
@.*. *.A^ .a*.
很明显,最短的路径应该是(0,0)-->(0,1)-->(1,1)-->(2,1)-->(1,1)-->(1,2)-->(1,3)就ok了,但是看看,我们为了去拿钥匙,不得不重复走了(1,1),那么这个应该如何来判重呢?
我们发现,一个点最多只能走两次,并且是没有钥匙的走一次,有钥匙的走一次,这样才会使答案最优!
这样我们就可以在原来的判重hash上加一维,来表示钥匙的状态,h[x][y][0]表示 没有钥匙时(x,y)是否走过 , h[x][y][1] 表示 有钥匙时(x,y)是否走过。 这样就可以轻松解决上面的问题了
C++ Code
/*
C++ Code
http://blog.csdn.net/jiangzh7
By Jiangzh
*/
#include<cstdio>
#include<queue>
using namespace std;
const int MAXN=50;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
int n,m,T;
char map[MAXN][MAXN];
struct status{int x,y,key,step;};
status first;
int h[MAXN][MAXN][2];
int tx,ty;
queue<status> q;
void read()
{
freopen("escape.in","r",stdin);
freopen("escape.out","w",stdout);
scanf("%d%d%d\n",&n,&m,&T);
for(int i=0;i<n;i++)
{
scanf("%s\n",map[i]);
for(int j=0;j<m;j++)
{
if(map[i][j]=='@') {first.x=i;first.y=j;}
if(map[i][j]=='^') {tx=i;ty=j;}
}
}
}
status change(status node,int k)
{
node.x+=dx[k];
node.y+=dy[k];
node.step++;
if(node.x>=0&&node.x<n&&node.y>=0&&node.y<m)
if(map[node.x][node.y]=='a')
node.key=1;
return node;
}
bool check(status node)
{
int x=node.x,y=node.y;
if(x<0 || x>=n || y<0 || y>=m) return false;
if(map[x][y]=='*') return false;
if(map[x][y]=='A' && !node.key) return false;
if(h[x][y][node.key]) return false;
return true;
}
void work()
{
q.push(first);
status tmp,newtmp;
while(!q.empty())
{
tmp=q.front();q.pop();
for(int k=0;k<4;k++)
{
newtmp=change(tmp,k);
if(check(newtmp))
{
if(newtmp.x==tx && newtmp.y==ty)
{
printf("%d",newtmp.step);
exit(0);
}
q.push(newtmp);
h[newtmp.x][newtmp.y][newtmp.key]=true;
}
}
}
printf("-1");
}
int main()
{
read();
work();
return 0;
}