牛客寒假算法基础集训营4 C题 Applese走迷宫

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

精通程序设计的 Applese 双写了一个游戏。

在这个游戏中,它被困在了一个
n×m的迷宫中,它想要逃出这个迷宫。

在迷宫中,有一些方格是水池,只有当 Applese 处于水属性的时候才可以通过;有一些方格是岩浆,只有当 Applese 是火属性的时候可以通过;有一些方格是墙壁,无论如何都无法通过;另一些格子是空地(包括起点和终点),可以自由通过。

在一些空地上有神秘道具可以让 Applese 转换自己的属性(从水属性变为火属性或从火属性变为水属性,需要一个单位的时间)。

已知 Applese 在一个单位的时间内可以朝四个方向行走一格,且开始处于水属性,位于空地的道具拾取后只能在该处立即使用(或者不使用),且可以多次使用。求它走出迷宫需要的最少时间。

输入描述:

第一行两个正整数 n, m 表示迷宫的大小。
接下来 n 行,每行长度为 m 的字符串。描述地图。
其中 ‘S’ 表示起点,‘T’ 表示终点,’.’ 表示空地,‘w’表示岩浆,’~‘表示水池,’@’ 表示道具,’#'表示障碍。
保证地图中的起点和终点只有一个,道具都位于空地。

输出描述:

输出一个整数,表示 Applese 走出迷宫的最短时间。特别地,如果 Applese 走不出迷宫,输出 “-1”。

示例1

输入

5 5
.w@…
.S#…
~w#…
.w…~
@w.~T

输出

18

备注

1≤n,m≤100

代码


package SearchDFSandBFS;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;

public class NewCowMazeBFS {

	static int sx,sy;//起始点坐标
	static int ex,ey;//终点坐标
	static int m,n;//m行n列
	static int[][][] vis=new int[105][105][2];
	static char[][] vans=new char[105][105];

	//0和~ 为1 
	//1和w 为1
	// ~ 为 0
	// w 为 1 
	// (0^0) ==0 (1^1)==0
	// (0^1)==1 (1^1)==0
	
	static class Node implements Comparable<Node>{
		int x,y;
		int ans;
		int status;//0为水属性 1为火属性
		Node(int x,int y,int status,int ans){
			this.x=x;this.y=y;this.status=status;
			this. ans=ans;
		}
		public int compareTo(Node o) {
			return this.ans-o.ans;
		}
	}
	static int [] dx= {-1,0,1,0};
	static int [] dy= {0,1,0,-1};
	static int bfs(int x,int y) {
		Queue<Node>q=new PriorityQueue<Node>();
	//	vis[x][y][0]=1; //初始为水属性
		q.add(new Node(x,y,0,0));
		while(!q.isEmpty()) {
			Node p=q.poll();
			if(vis[p.x][p.y][p.status]==1) continue;
			vis[p.x][p.y][p.status]=1;
			if(p.x==ex&&p.y==ey) {
				return p.ans;
			}
			for(int i=0;i<4;i++) {
				int xx=p.x+dx[i];
				int yy=p.y+dy[i];
				
				if(xx<0||xx>=m||yy<0||yy>=n||vans[xx][yy]=='#')  continue; 
				char ch=vans[xx][yy];
				if(ch=='.'||ch=='S'||ch=='T') {
					q.add(new Node(xx,yy,p.status,p.ans+1));
				}else if(ch=='@') {
					q.add(new Node(xx,yy,p.status,p.ans+1));
					q.add(new Node(xx,yy,(p.status^1),p.ans+2));
				}else {
					int status =ch=='w'?1:0;
					if((p.status^status)==0) {
						q.add(new Node(xx,yy,p.status,p.ans+1));
					}
				}
			}
		}
		return -1;
	}
	public static void main(String[] args) throws IOException {
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
			StringTokenizer token=new StringTokenizer(br.readLine());
			m=Integer.parseInt(token.nextToken());
			n=Integer.parseInt(token.nextToken());
			for(int i=0;i<m;i++) {
				String str=br.readLine();
				for(int j=0;j<n;j++) {
					vis[i][j][0]=0;
					vis[i][j][1]=0;
					char ch=str.charAt(j);
					if(ch=='S') {
						sx=i;sy=j;
					}
					if(ch=='T') {
						ex=i;ey=j;
					}
					vans[i][j]=ch;
				}
			}
				System.out.println(bfs(sx,sy));
	}

			
}


迷宫问题,求解最短路程一般使用bfs的方法,因为使用队列的问题,只要到达了终点就输出结果,结果就为最短路径的答案。

这里需要注意的是队列的选择,应该优先级队列PriorityQueue,并且使Node结点根据步数来排序,即步数最短的结点放在队列的前头,如果不实现Node的可比性并且选择的是LinkedList队列,只会通过百分之50的数据。

与经典的bfs不同的是,标记是否加入队列的数组应该设置为3维,即对不同的状态访问同一个位置是两种不同的情况。比如访问(xx,yy,~)时状态为1,应该标记vis[xx][yy][1]=1,再次达到这个点时如果状态为1,可以对这个结点的上下左右进行访问。

使用位与(异或)计算来实现状态的改变。
0代表水状态,1代表火状态。如果跳到@时,0状态变为1,1状态要变为0,所以跳到@时将这个结点的状态位与1进行异或并生成新的结点加入到队列中。
设置临时变量status,如果跳到w时status设置为1,跳到~status设置为0,将status和当前访问的结点的状态为进行异或如果为0就生成新的结点加入队列中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值