hdoj 1175 连连看 bfs+优先队列(Java版)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1175
题目:“连连看”相信很多人都玩过。没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子。如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去。不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的。现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过。
玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能不能消去。现在你的任务就是写这个后台程序。

题解:
最开始没注意到的坑点:
bfs+优先队列,最开始没用优先队列,wa了好几发,后来看了讨论区里一位朋友的测试数据,发现开始点和结束点倒过来竟然结果不一样。
突然明白虽然你这样能求出最短的路程,但是有可能多转弯了几次,结果就变NO了,所以要用优先队列让转弯次数少的先出队列。
其他的要点和解释在代码注释中
代码:


import java.util.PriorityQueue;
import java.util.Scanner;
//bfs+优先队列,最开始没用优先队列,wa了好几发,后来看了讨论区里一位朋友的测试数据,发现开始点和结束点倒过来竟然结果不一样。
//突然明白虽然你这样能求出最短的路程,但是有可能多转弯了几次,结果就变NO了,所以要用优先队列让转弯次数少的先出队列。
public class Main {
	static int n,m,q;
	static boolean isin(int a,int b){//判断是否在地图内
		return a>0&&a<=n&&b>0&&b<=m;
	}
	static int res[][]={{1,0},{-1,0},{0,1},{0,-1}};//上下左右移动
	static class point implements Comparable<point>{
		int x,y,step;//坐标点,当前折叠次数
		char direction;//上一次的折叠方向
		public point(int x, int y, int step, char direction) {
			this.x = x;
			this.y = y;
			this.step = step;		
			this.direction = direction;
		}
		@Override
		public int compareTo(point o) {//step小的先出队列
			return this.step-o.step;
		}
		
	}
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);	
		while(true){
			n=sc.nextInt();
			m=sc.nextInt();
			if(n==0&&m==0)
				break;
			int map[][]=new int[n+1][m+1];
			for(int i=1;i<=n;i++){
				for(int j=1;j<=m;j++){
					map[i][j]=sc.nextInt();
				}
			}
			q=sc.nextInt();
			int x1,y1,x2,y2;
			for(int i=0;i<q;i++){
				x1=sc.nextInt();
				y1=sc.nextInt();
				x2=sc.nextInt();
				y2=sc.nextInt();
				if(map[x1][y1]!=map[x2][y2]||map[x1][y1]==0){//如果起点和终点不一样或者有一个是0就不能消除
					System.out.println("NO");
					continue;
				}	
				if(x1==x2&&y1==y2){//起点和终点相等也不能消除
					System.out.println("NO");
					continue;
				}
				boolean vis[][]=new boolean[n+1][m+1];	//判断是否访问过		
				PriorityQueue<point> q=new PriorityQueue<>();
				q.add(new point(x1,y1,-1,'a'));//起点入队列,因为起点没有上一步走的方向,所以我用‘a’代替,这样相当于多转了一个弯
				vis[x1][y1]=true;              //所以step初始化为-1,为0也可以,判断条件变成3就好
				boolean flag=false;//标记是否能消除成功
				while(!q.isEmpty()){
					point tp=q.poll();
					int x=tp.x;
					int y=tp.y;
					int step=tp.step;
					char direction=tp.direction;
					if(step>2){//如果折叠超过2次就消除失败
						break;
					}
					if(x==x2&&y==y2){
						flag=true;						
						break;
					}
					for(int j=0;j<4;j++){
						int tx=x+res[j][0];
						int ty=y+res[j][1];
						if((isin(tx,ty)&&!vis[tx][ty]&&map[tx][ty]==0)||(tx==x2&&ty==y2)){//如果下一个点是终点或者是0且未被访问过的且在地图内的
							if(j==0){//自定义四个方向
								char t_direction='D';
								if(t_direction==direction){
									q.add(new point(tx,ty,step,t_direction));
									vis[tx][ty]=true;
								}else{
									q.add(new point(tx,ty,step+1,t_direction));//跟上一次折叠的方向不一样就step+1
									vis[tx][ty]=true;
								}
							}else if(j==1){
								char t_direction='U';
								if(t_direction==direction){
									q.add(new point(tx,ty,step,t_direction));
									vis[tx][ty]=true;
								}else{
									q.add(new point(tx,ty,step+1,t_direction));
									vis[tx][ty]=true;
								}
							}else if(j==2){
								char t_direction='L';
								if(t_direction==direction){
									q.add(new point(tx,ty,step,t_direction));
									vis[tx][ty]=true;
								}else{
									q.add(new point(tx,ty,step+1,t_direction));
									vis[tx][ty]=true;
								}
							}else{
								char t_direction='R';
								if(t_direction==direction){
									q.add(new point(tx,ty,step,t_direction));
									vis[tx][ty]=true;
								}else{
									q.add(new point(tx,ty,step+1,t_direction));
									vis[tx][ty]=true;
								}
							}
						}
					}
					
				}
				if(flag){
					System.out.println("YES");
				}else{
					System.err.println("NO");
				}
			}
		}
		sc.close();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值