胜利大逃亡(续)(简单的深搜+状态压缩)

Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)……

Output
针对每组测试数据,如果可以成功逃亡,请输出需要多少分钟才能离开,如果不能则输出-1。
Sample Input
4 5 17
@A.B.
a*..
^
c…b

4 5 16
@A.B.
a*..
^
c…b

Sample Output
16
-1
**

解题思路:

**
这道题的巧妙之处在于将状态压缩成一个整型数据,即状态压缩
状态压缩的方法,就是利用二进制数的零一进行模拟。零代表没取,一代表取了。
这道题还涉及到队列的一些知识来源:百度百科

代码:

#include<iostream>
#include<string>
#include<queue>
#include<algorithm>
#include<vector>
#include<memory.h>
#include<vector>
#include<map>
using namespace std;

int n,m,t;                       //题目给定的 3个 变量 

struct point{                      
	int x;                         //横坐标 
	int y;                          //纵坐标 
	int state;                       //钥匙 
	int time;                        //用时 
	point(int a,int b,int c,int d){
		x=a;                            
		y=b;
		state=c;
		time=d;
	}
	point(){
	}
};
char maze[25][25];                         //字符型数组记录位置的坐标 
bool vis[25][25][1<<11];                 //1<<11是将有没有钥匙的状态压缩为一个整型,因为电脑中数据为二进制 ,01可以表示不同状态

int dx[4]={0,1,-1,0};
int dy[4]={1,0,0,-1};                    //用 2个 数 组可以表示上下左右移动

int bfs(point start,point end){            //定义深搜函数 

  
queue<point>que;                          //定义一个队列 
que.push(start);                        //将开始的坐标收近队列中 
vis[start.x][start.y][start.state]=1;   //标记开始的坐标,表示已经搜索过 
while(!que.empty()){                       //当队列不为空,即还有没有搜索过的坐标 
	
	point tp=que.front();                //弹出队列的第一个元素 
 	que.pop();                            //移除队列的第一个元素 
 	
	if( tp.x==end.x&&tp.y==end.y)        //如果该坐标为出口坐标,表示已经走出迷宫 
	  return tp.time;                      //返回走的时间 
	for(int i=0;i<4;i++){                  //搜索能走的路 ,上下左右 
		int x=tp.x+dx[i];
		int y=tp.y+dy[i];
		int s=tp.state;
		int t=tp.time;
	
	if(vis[x][y][s]==0&&maze[x][y]!='*'){    //如果没有搜索过 且  不是墙"*" 
		vis[x][y][s]=1;                       //标记该坐标,表示已经搜索过 
	                                                  //如果该处不是路 ,可能是门, 可能是钥匙 
		if(maze[x][y]>='a'&&maze[x][y]<='j'){       //如果该处是钥匙 
		
			s=s|(1<<(maze[x][y]-'a'));            //maze[x][y]-a表示是哪一个门的钥匙 (比如是 j,它和 a 相差 10 ,1就左移 10) 		  	
										               //(接上面)此时1为100000000,然后和原来的钥匙状态取 位或 ,即已取了这个钥匙 
				                                        //(接上面)比如说它原来有 a 钥匙,则s=0000000001取了 j 钥匙,则为10000000001 
		
			vis[x][y][s]=1;                         //标记该状态 
			que.push(point(x,y,s,t+1));             //将该状态放入队列中 ,此时时间应加  1,因为走了一步 
		}
	else
		if(maze[x][y]>='A'&&maze[x][y]<='J'){          //若此处为门 
		if( s&(1<<(maze[x][y]-'A'))){           //看是否有该门的钥匙 ,比如 J 门为10000000000,若有  j和 a,则s=1000000001 
		  			                                     //(接上面) 两者取  位与  ,不为0,表示有钥匙,可搜索          
		 
			vis[x][y][s]=1;    
			que.push(point(x,y,s,t+1));
		}}
		else{
			que.push(point(x,y,s,t+1));
		
	}

	
}


} }
return -1;
}
int main(){

	while(~scanf("%d %d %d",&n,&m,&t)&&n&&m&&t){
	memset(vis,0,sizeof(vis));           //初始化数组 
	for(int i=0;i<=n+1;i++){
		for(int j=0;j<=m+1;j++){
			maze[i][j]='*';            //初始化数组 
		}
	}
	point s,e;
	for(int i=1;i<=n;i++){        
		for(int j=1;j<=m;j++){
		cin>>maze[i][j];
		if(maze[i][j]=='@'){     
		 s=point(i,j,0,0);          //用结构体记录该点坐标 
			maze[i][j]='.';         //该点标记为路 
		}
		if(maze[i][j]=='^'){
		e=point(i,j,0,0);
			maze[i][j]='.';
		}
		}
	}
	int ans=bfs(s,e);                    //深搜 
	if(ans==-1||ans>=t) cout<<-1<<endl;
	else cout<<ans<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值