HDU-1254 java 实现 bfs+bfs,方向剪枝

推箱子

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 9635    Accepted Submission(s): 2835


Problem Description
推箱子是一个很经典的游戏.今天我们来玩一个简单版本.在一个M*N的房间里有一个箱子和一个搬运工,搬运工的工作就是把箱子推到指定的位置,注意,搬运工只能推箱子而不能拉箱子,因此如果箱子被推到一个角上(如图2)那么箱子就不能再被移动了,如果箱子被推到一面墙上,那么箱子只能沿着墙移动.

现在给定房间的结构,箱子的位置,搬运工的位置和箱子要被推去的位置,请你计算出搬运工至少要推动箱子多少格.


 

Input
输入数据的第一行是一个整数T(1<=T<=20),代表测试数据的数量.然后是T组测试数据,每组测试数据的第一行是两个正整数M,N(2<=M,N<=7),代表房间的大小,然后是一个M行N列的矩阵,代表房间的布局,其中0代表空的地板,1代表墙,2代表箱子的起始位置,3代表箱子要被推去的位置,4代表搬运工的起始位置.
 

Output
对于每组测试数据,输出搬运工最少需要推动箱子多少格才能帮箱子推到指定位置,如果不能推到指定位置则输出-1.
 

Sample Input
 
 
15 50 3 0 0 01 0 1 4 00 0 1 0 01 0 2 0 00 0 0 0 0
 

Sample Output
 
 
4

 


思路:

如果这个箱子不用人来移动,自己就可以移动,那么这道题就是一个最简单的bfs题。但是这道题的问题在于箱子需要人来推,而人不一定能够到达推箱子的位置。那么我们需要另外写一个bfs,来判断当前情况中,人能不能到达这个位置。这个bfs形式上是很简单的,没有多余条件,只需要传入路径,起始位置,结束位置,然后每个位置不能到两次,简单剪个枝,返回true or false 就行了。但是接下来又有一个问题:路径是会改变的。每次移动箱子,人的位置会变,路径也会变。那么相当于人和路径都是跟着箱子走的,是箱子的一个属性。同样的要写进Node类里,跟着Node对象走。最后就是箱子是可以到同一个位置两次的。但是如果你就直接四个方向什么都不管地搜索,这样是要超时的。解决办法就是vis的三维数组记录,同样的方向不能到达两次,这样来剪枝。
代码:


import java.util.LinkedList;  
import java.util.Queue;
import java.util.Scanner;
public class Main {
     static int[][] road;
     static boolean[][][] vis;
     static boolean[][] visman;
     static int[][] dir={{0,1},{1,0},{0,-1},{-1,0}}; //第一组是向右,二是向下,三是向左,四是向上
     static Node start;
     static Node end;
     static man man123;
     static int M,N;
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
      Scanner cin=new Scanner(System.in);
      int T=cin.nextInt();
      while(T-->0)
      {
    	  M=cin.nextInt();
    	  N=cin.nextInt();
    	  road=new int[M][N];
    	  vis=new boolean[M][N][4] ;
    	  for(int i=0;i<M;i++)
    	  {
    		  for(int j=0;j<N;j++)
    		  {
    			  road[i][j]=cin.nextInt();
    			  if(road[i][j]==2)start=new Node(i,j,0,0);
    			  if(road[i][j]==3)end=new Node(i,j,0,0);
    			  if(road[i][j]==4)man123=new man(i,j);
    		  }
    	  }
    	  start.mann=man123;
    	  for(int i=0;i<M;i++)
    	  {
    		  for(int j=0;j<N;j++)
    		  {
    			  start.roadd[i][j]=road[i][j];
    		  }
    	  }
    	  System.out.println(bfs(road));
    	  
      }
	}
	
	static int bfs(int[][] road)
	{
		Queue<Node> queue=new LinkedList<Node>();
		queue.add(start);
		while(!queue.isEmpty())
		{
			Node node=queue.poll();
			if(node.x==end.x&&node.y==end.y)return node.number;
			vis[node.x][node.y][node.direct]=true;
			for(int i=0;i<4;i++)
			{
			  	 visman=new boolean[M][N];
				 int new_row=node.x+dir[i][0];
				 int new_col=node.y+dir[i][1];
				 if(new_row<0||new_col<0||new_row>=M||new_col>=N||vis[new_row][new_col][i]==true)continue;
				 if(i==0||i==2)
				 {
					 int yy=node.y-dir[i][1];    
					 if(yy<0||yy>=N)continue; //箱子两边都要有位置,为防止数组越界,先判断有没有位置,再判断是不是墙
					 else 
					 if(road[node.x][node.y+dir[i][1]]==1||road[node.x][node.y-dir[i][1]]==1)continue;
				 }
				 if(i==1||i==3)
				 {
					 int xx=node.x-dir[i][0];
					 if(xx<0||xx>=M)continue;
					 else
					 if(road[node.x+dir[i][0]][node.y]==1||road[node.x-dir[i][0]][node.y]==1)continue;
				 }
	             if(i==0||i==2)
	             {
	             	 
	            	 if(bfsman(node.roadd,node.mann,new man(node.x,node.y-dir[i][1]))){
				    	  Node nn=new Node(new_row,new_col,node.number+1,i);
				    	  for(int m=0;m<M;m++)   //这个for的作用就是路径的改变是在上一次路径的基础之上,而不是最初的那个路径,所以先赋值
				    	  { 
				    		  for(int n=0;n<N;n++)
				    		  {
				    			  nn.roadd[m][n]=node.roadd[m][n];
				    		  }
				    	  }
				    	  nn.mann=new man(node.x,node.y);
				    	  nn.roadd[node.x][node.y+dir[i][1]]=2;
				    	  nn.roadd[node.x][node.y]=0;
				    	  queue.offer(nn);
				      }
	             }
	             else if(i==1||i==3)
	             {
	             	
	            	 if(bfsman(node.roadd,node.mann,new man(node.x-dir[i][0],node.y))){
				    	  Node nn=new Node(new_row,new_col,node.number+1,i);
				    	  for(int m=0;m<M;m++)
				    	  {
				    		  for(int n=0;n<N;n++)
				    		  {
				    			  nn.roadd[m][n]=node.roadd[m][n];
				    		  }
				    	  }
				    	  nn.mann=new man(node.x,node.y);
				    	  nn.roadd[node.x+dir[i][0]][node.y]=2;
				    	  nn.roadd[node.x][node.y]=0;
				    	  queue.offer(nn);
				      }
	             }
	             
			}
		}
		return -1;
	}
	
	static boolean bfsman(int[][] road,man start,man end)
	{
		Queue<man> queue=new LinkedList<man>();
		queue.add(start);
		while(!queue.isEmpty())
		{
			man node=queue.poll();
			visman[node.x][node.y]=true;
			if(node.x==end.x&&node.y==end.y)return true;
			for(int i=0;i<4;i++)
			{
				int row=node.x+dir[i][0];
				int col=node.y+dir[i][1];
				if(row<0||col<0||row>=M||col>=N||road[row][col]==2||road[row][col]==1||visman[row][col]==true)continue;
				man nn=new man(row,col);
				queue.offer(nn);
			}
		}
		return false;
	}
	
	static class Node
	{
		int x;
		int y;
		int number;
		int[][] roadd=new int[M][N];
		man mann=new man();
		int direct=-1;
		Node(int xx,int yy,int num,int dd)
		{
			x=xx;
			y=yy;
			number=num; 
			for(int i=0;i<M;i++)
			{
				for(int j=0;j<N;j++)
				{
					roadd[i][j]=road[i][j];
				}
			}
			direct=dd;
		}
		public Node() {
			// TODO 自动生成的构造函数存根
		}
	}
	static class man
	{
		int x;
		int y;
		man(int xx,int yy)
		{
			x=xx;
			y=yy;
		}
		public man() {
			// TODO 自动生成的构造函数存根
		}
	}
    
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值