HDU 1429-胜利大逃亡(续)

A - 胜利大逃亡(续)
Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Appoint description: 

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
 

思路:
   这题一开始认为是直接求出钥匙与门之间的距离就能人走到门那里直接加刚刚求出的距离,就OK了。结果写好才发现根本思路是错的,而且代码非常复杂,两个结构体,3,4个函数。最后看了看题解,都说是增加钥匙状态去当标记,这样就能走重复过的x,y了,巧妙。最后wa了两次,因为不记得比较第几把钥匙Wa了。

总结:
   之前是想用容器去将钥匙的情况的存储起来结果发现复杂度太高了,而且不能保证能全部遍历一次, 所以做了这题后,我发现其实增加维数在搜索里就是一种暴力求解的工具。


AC代码:

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<cstdio>
#include<map>
using namespace std;
#define T 1000005
int n,m,t;
char str[30][30];
bool vis[30][30][1<<11];
int fx[][2] = {{1,0},{0,1},{-1,0},{0,-1}};
bool jugde(int x,int y,int& key)
{
	if(x>=0&&x<n&&y>=0&&y<m&&str[x][y]!='*'&&!vis[x][y][key]){
		if(str[x][y]>='a'&&str[x][y]<='z'){
					key|= (1<<(str[x][y]-'a'));
					return true;
				}
		else if(str[x][y]=='.'||str[x][y]>='A'&&str[x][y]<='Z'&&((key>>(str[x][y]-'A'))&1))
		return true;
		else if(str[x][y]=='@'){
			return true;
		}
	}
	return false;
}
struct point
{
	int x,y,key,cnt;
	point(int _x,int _y,int _cnt,int _key):x(_x),y(_y),cnt(_cnt),key(_key){}
	point(){}
}p[T],q;
int bfs(int x,int y,int xx,int yy)
{
	int head=0,tail=0;
	int i,tx,ty,key;
	p[tail].key = 0;
	p[tail].x = x,p[tail].y = y,p[tail++].cnt = 0;
	vis[x][y][0] = true;
	while(head<tail)
	{
		q = p[head++];
		for(i=0;i<4;++i){
			tx = q.x + fx[i][0];
			ty = q.y + fx[i][1];
			key = q.key;
			if(tx==xx&&ty==yy){
				return q.cnt+1;
			}
			int key1 = key;
			if(jugde(tx,ty,key)){
				if(key!=key1)vis[tx][ty][key1] = true;
				vis[tx][ty][key] = true;
				p[tail++] = point(tx,ty,q.cnt+1,key);
			}
		}
	}
	return -1;
}
void Init()
{
		memset(vis,false,sizeof(vis));
}
int main()
{
#ifdef zsc
	freopen("input.txt","r",stdin);
#endif
	int x,y,i,k;
	int xn,yn;
	while(~scanf("%d%d%d",&n,&m,&t))
	{
		memset(vis,false,sizeof(vis));
		for(i=0;i<n;++i){
			for(k=0;k<m;++k){
				scanf("\n%c",&str[i][k]);
				if(str[i][k]=='@'){
					x = i,y=k;
				}
				if(str[i][k]=='^'){
					xn=i,yn=k;
				}
			}
		}
		int tmp = bfs(x,y,xn,yn);
		if(tmp<t&&tmp!=-1){
			printf("%d\n",tmp);
		}
		else
		{
			printf("-1\n");
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值