hdu 1429 胜利大逃亡(续)

链接:点击打开链接

思路:刚开始我想的是两个bfs,来找最少的时间,就是先找门,根据门在找钥匙。但是WA,果断是想简单啦。如果在找门的途中就可以找到钥匙,就不要返回去找啦,所以我的想法错啦。后面是看解题报告,要用二进制位运算来做,其实标记数组加一维来计算拾到的钥匙。发现好多题都是这个标记数组牛逼啦,太他妈神啦。。

用二进制来表示手头的钥匙有哪些,100表示有第三把钥匙,111表示有第三、二、一把,搜索下一点时,如果该点为钥匙点,则可采用|运算来模拟拾取,显然0001 | 1000 = 1001,同理,当为相应的门时采用&运算来模拟开启,例如1101 & 0001 = 0001(即可以打开'A'门)

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
struct node{
	int x;
	int y;
	int time;
	int nkey;
	};
bool vis[30][30][1025];
int n,m,t,a[4][2]={{0, 1}, {0, -1}, {-1, 0}, {1, 0}};;
int map[30][30],fx,fy,ex,ey;
void bfs(){
	int i,xx;
	queue<node>Q;
	node p,q;
	p.x=fx;
	p.y=fy;
	p.time=0;
	p.nkey=0;
	vis[p.x][p.y][p.nkey]=1;
	Q.push(p);
	while(!Q.empty()){
		p=Q.front();
		Q.pop();
		for(i=0;i<4;i++){
			q=p;
			q.x=p.x+a[i][0];
			q.y=p.y+a[i][1];
			q.time++;
		  if(q.x>=1&&q.x<=n&&q.y>=1&&q.y<=m&&map[q.x][q.y]!='*'&&q.time<t){
			if(q.x==ex&&q.y==ey){
			printf("%d\n",q.time);
			return;
			}
			//	if(q.time>t) continue;
				 if(map[q.x][q.y]>='a'&&map[q.x][q.y]<='z'){
						xx=(1<<(map[q.x][q.y]-'a'));
						q.nkey|=xx;
						if(!vis[q.x][q.y][q.nkey]){
						vis[q.x][q.y][q.nkey]=1;
			            Q.push(q);
					     }
						}
				 else if(map[q.x][q.y]>='A'&&map[q.x][q.y]<='Z'){
						 xx=(map[q.x][q.y]-'A');
						if(((q.nkey>>xx)&1)&&!vis[q.x][q.y][q.nkey]){
							vis[q.x][q.y][q.nkey]=1;
							Q.push(q);
							}
					}
				 else  if(!vis[q.x][q.y][q.nkey]){
						vis[q.x][q.y][q.nkey]=1;
						Q.push(q);
						}			
				} 
			}
		}
			printf("-1\n");
}
int main(){
	int i,j,k=0;
	while(~scanf("%d %d %d",&n,&m,&t)){
	//	if(k!=0)
	//	cout<<endl;
	//	k++;
		for(i=1;i<=n;i++){
			getchar();
			for(j=1;j<=m;j++){
				scanf("%c",&map[i][j]);
				if(map[i][j]=='@'){
					fx=i;
					fy=j;
					}
				else if(map[i][j]=='^'){
					ex=i;
					ey=j;
					}	
				}
			}
				memset(vis,0,sizeof(vis));
				bfs();
		}
		return 0;
	}	


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值