用深搜解决图论四连通检测问题

问题描述:

  给定一个方阵,定义连通性:上下左右相邻,并且值相同。可以想象一张地图,不同的区域被染成了不同的颜色。现在我们需要判断图中任意两点是否在同一个连通区间中。

输入:

整数N(N<50),代表矩阵的行列数

输入N行,每行N个字符,代表矩阵中的元素

输入一个整数M(M<1000)表示询问次数

输入M行每行代表一个询问,格式为4个整数x1 y1 x2 y2,代表需要检测的点

输出:

true或false

测试数据:
10
0 0 1 0 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0
0 0 0 0 1 1 1 1 1 0
0 0 0 1 1 0 0 0 1 0
1 1 1 1 0 1 0 0 1 0
0 0 0 0 0 1 0 0 1 0
0 0 0 0 0 1 0 0 1 1
0 1 1 1 1 1 1 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0
3
0 0 9 9
0 2 6 8
4 4 4 6

输出结果应为:
true
false
false

解题思路:
  从给定的起点开始进行深搜,看是否能走到给定的终点。在深搜过程中每个位置依次向四个方向进行深搜(上,下,左,右)。从深搜树状图来看,每一个节点有四个分支。需要注意的是回溯;由于这题是问两个点是否能连通,而不是问有多少条相通的路径。所以回溯的时候不能将visited[][]对应的位置重新标记为零

代码如下:

import java.util.Scanner;

public class 四联通块 {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int N = scanner.nextInt();  
		int[][]	 map = new int[N][N];
		for(int i=0; i<N; i++){
			for(int j=0; j<N; j++){
				map[i][j] = scanner.nextInt();
			}
		}
		int M = scanner.nextInt();  //询问的次数
		int[][] points = new int[M][4];  //起点和终点的集合
		for(int i=0; i<M; i++){
			for(int j=0; j<4; j++){
				points[i][j] = scanner.nextInt();
			}
		}
		//打印结果
		for(int i=0; i<M; i++){
			System.out.println(checkDFS(map, new int[N][N], points[i]));
		}
	}

	//深搜检测两点是否想通
	private static boolean checkDFS(int[][] map, int[][] visited, int[] points) {
		int x1 = points[0], y1 = points[1];  //起点坐标
		int x2 = points[2], y2 = points[3];  //终点坐标
		boolean up = false;   
		boolean down = false;  
		boolean right = false; 
		boolean left = false;  
		
		//当从起点走到终点时,说明起点和终点想通
		if(x1==x2 && y1==y2){
			return true;
		}
		
		//向左走 要保证不越界 且下一个位置没有访问过 且数字是相同的(即两个位置在同一块上)
		if(x1-1>=0 && visited[x1-1][y1]==0 && map[x1-1][y1]==map[x1][y1]){
			visited[x1-1][y1] = 1;   //标记走过的位置
			points[0] = x1-1;  //修改起点的位置
			left = checkDFS(map, visited, points);
			//visited[x1-1][y1] = 0;  //此路不通时, 回溯
			//因为只是判断两个点是否想通,而不是找两个点有多少条向通的路径,
			//所以回溯时不能将visited[x1-1][y1] = 0
			points[0] = x1;
		}
		//向右走
		if(x1+1<map.length && visited[x1+1][y1]==0 && map[x1+1][y1] == map[x1][y1]){
			visited[x1+1][y1] = 1;
			points[0] = x1+1;
			right = checkDFS(map, visited, points);
			//visited[x1+1][y1] = 0; //回溯 
			points[0] = x1;
		}
		//向上走
		if(y1-1>=0 && visited[x1][y1-1]==0 && map[x1][y1-1]==map[x1][y1]){
			visited[x1][y1-1] = 1;
			points[1] = y1-1;
			up = checkDFS(map, visited, points);
			//visited[x1][y1-1] = 0;  //回溯 
			points[0] = y1;
		} 
		//向下走
		if(y1+1<map.length && visited[x1][y1+1]==0 && map[x1][y1+1]==map[x1][y1]){
			visited[x1][y1+1] = 1;
			points[1] = y1+1;
			up = checkDFS(map, visited, points);
			//visited[x1][y1+1] = 0;  //回溯 
			points[0] = y1;
		}
		
		return up || down || right || left;
	}
}




改进后的代码如下(将四个if用一个for循环实现):

import java.util.Scanner;

public class 四联通块解法二 {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int N = scanner.nextInt();  
		int[][]	 map = new int[N][N];
		for(int i=0; i<N; i++){
			for(int j=0; j<N; j++){
				map[i][j] = scanner.nextInt();
			}
		}
		int M = scanner.nextInt();  //询问的次数
		int[][] points = new int[M][4];  //起点和终点的集合
		for(int i=0; i<M; i++){
			for(int j=0; j<4; j++){
				points[i][j] = scanner.nextInt();
			}
		}
		//打印结果
		for(int i=0; i<M; i++){
			System.out.println(checkDFS(map, new int[N][N], points[i]));
		}
	}

	//深搜检测两点是否想通
	private static boolean checkDFS(int[][] map, int[][] visited, int[] points) {
		int x1 = points[0], y1 = points[1];  //起点坐标
		int x2 = points[2], y2 = points[3];  //终点坐标
		int ex =0, ey =0;  //将要进入位置的坐标
		int[] dx= {1,0,-1,0}, dy={0,1,0,-1}; //控制方向:右,下,左,上
		
		//当从起点走到终点时,说明起点和终点想通
		if(x1==x2 && y1==y2){
			return true;
		}
		
		//依次尝试四个方向的深搜
		for(int i=0; i<4; i++){
			ex = x1 + dx[i];
			ey = y1 + dy[i];
			//判断是否越界
			if(ex<0||ex>=map.length || ey<0||ey>=map.length){
				continue;
			}
			//保证要进入的位置没有被访问过,且在同一块内(即数字相同)
			if(visited[ex][ey]==0 && map[ex][ey]==map[x1][y1]){
				visited[ex][ey] = 1;
				points[0] = ex;
				points[1] = ey;
				if(checkDFS(map, visited, points)){
					return true;
				}
				//回溯
				points[0] = x1;
				points[1] = y1;
			}
		}
		return false;
	}
}

猜你喜欢

转载自blog.csdn.net/HC199854/article/details/106605732