藍橋杯-迷宮問題(圖)

...11111111111111111111111111111
11.111111........1111111111.1111
11.111111..111.11111111.....1111
11.11111111111.1111111111.111111
11.111111.................111111
11.111111.11111111111.11111.1111
11.111111.11111111111.11111..111
11..........111111111.11111.1111
11111.111111111111111.11....1111
11111.111111111111111.11.11.1111
11111.111111111111111.11.11.1111
111...111111111111111.11.11.1111
111.11111111111111111....11.1111
111.11111111111111111111111.1111
111.1111.111111111111111......11
111.1111.......111111111.1111.11
111.1111.11111.111111111.1111.11
111......11111.111111111.1111111
11111111111111.111111111.111...1
11111111111111...............1.1
111111111111111111111111111111..

如上圖的迷宮,入口,出口分別:左上角,右下角
"1"是牆壁,"."是通路
求最短需要走多少步?

測試數據1:
21 32 
...11111111111111111111111111111
11.111111........1111111111.1111
11.111111..111.11111111.....1111
11.11111111111.1111111111.111111
11.111111.................111111
11.111111.11111111111.11111.1111
11.111111.11111111111.11111..111
11.................11.11111.1111
11111.111111111111.11.11....1111
11111.111111111111.11.11.11.1111
11111.111111111111.11.11.11.1111
111...111111111111.11.11.11.1111
111.11111111111111.11....11.1111
111.11111111111111.11111111.1111
111.1111.111111111.11111......11
111.1111.......111.11111.1111.11
111.1111.11111.111.11111.1111.11
111......11111.111.11111.1111111
11111111111111.111.11111.111...1
11111111111111...............1.1
111111111111111111111111111111..
答案:53
測試數據2:
21 32
...11111111111111111111111111111
11.111111........1111111111.1111
11.111111..111.11111111.....1111
11.11111111111.1111111111.111111
11.111111.................111111
11.111111.11111111111.11111.1111
11.111111.11111111111.11111..111
11..........111111111.11111.1111
11111.111111111111111.11....1111
11111.111111111111111.11.11.1111
11111.111111111111111.11.11.1111
111...111111111111111.11.11.1111
111.11111111111111111....11.1111
111.11111111111111111111111.1111
111.1111.111111111111111......11
111.1111.......111111111.1111.11
111.1111.11111.111111111.1111.11
111......11111.111111111.1111111
11111111111111.111111111.111...1
11111111111111...............1.1
111111111111111111111111111111..
答案:61


DFS做法

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
public class Main {
	
	//行號
	static int row ;
	//列號
	static int col ;
    public static void main(String[] args) throws FileNotFoundException { 
    	
    	
    	Scanner input = new Scanner(System.in);
    	//分割字符串,得到即將輸入二維數組的行和列
    	//" +"是一個正則表達式,代表安裝一個以上的空格進行分割
    	String[] ss = input.nextLine().trim().split(" +");
    	row = Integer.parseInt(ss[0]);
    	col = Integer.parseInt(ss[1]);;
    	
    	
    	
    	char[][] data = new char[row][col];
    	for(int i=0;i<row;i++){
    		data[i] = input.next().toCharArray();
    	}
    	
    	
    	
		System.out.println(min_path(data,0,0));
		
    }  
    
    public static int min_path(char[][] data,int x,int y){
    	//當走到最後一個位置 右下角的時候
    	//根據題目規定 我們是從 0,0出發的 
    	//假設 終點是 0,1  那麼走到終點應該返回一個0
    	//代表只走一步就到達了終點
    	//可以理解成: 從 0,0 走到 0,0 只需要 0 步
    	if(x==row-1&&y==col-1){
    		return 0;
    	}
    	
    	//走到該位置 加上標記防止 往回走 
    	data[x][y] = '*';
    	
    	//現在走到終點的最小步數   初始值爲Integer最大值 (-10 是爲了 防止在+1後溢出)
    	int min = Integer.MAX_VALUE-10;
    	
    	//嘗試向上走需要多少步。
		if (x > 0 && data[x-1][y]=='.') {
			//判斷該向上走需要的步數是否是最小步數
			min = Math.min(min, 1 + min_path(data, x - 1, y));
		}
		
		//向下
		if (x < row-1 && data[x+1][y]=='.') {
			min = Math.min(min, 1 + min_path(data, x + 1, y));
		}
		
		//向左
		if (y > 0 && data[x][y-1]=='.'){
			min = Math.min(min, 1 + min_path(data, x, y - 1));
		}
		
		//向右
		if (y < col-1 && data[x][y+1]=='.') {
			min = Math.min(min, 1 + min_path(data, x, y + 1));
		} 
		
		
		//回溯在遞歸測試完畢找到所有最短路徑後
		//將該位置復原 (既然可以走到該位置,該位置肯定是.)
		data[x][y] = '.';
		
		//如果,四個方向都沒有走通,那麼min還是初始值 Integer的最小值
		//代表該位置作廢 走不通
		return min;
    }
 
    
}  

注意:

 

這個問題的解法在二維數組的"走動"類問題上適用性上具有很好的普遍性,在解法中,可以將向上,向下,向左,向右的邏輯算法同時列舉, 但是這樣看起來不簡潔,可以使用一個小技巧,使用int[][] d 來操作上下左右的移動,詳見我的另一篇文章:

島嶼的數量:

https://blog.csdn.net/qq_35394891/article/details/84404156

迷宮問題要比島嶼的數量問題稍簡單

 

BFS做法

用本次的狀態去派生出下次的狀態,

直到有一次狀態裏有終點位置,說明找到了終點。

感覺比dfs快一點。

import java.util.*;
 
public class A
{
	// from: 出發位置  goal: 目標位置
	static int f(char[][] data, Set from, String goal){
		if(from.contains(goal)) return 0; // 達到了最終的位置
		
		Set set = new HashSet(); // 找到from的相鄰連通點
		
		for(Object obj: from){
			String[] ss = ((String)obj).split(",");
			int y = Integer.parseInt(ss[0]);
			int x = Integer.parseInt(ss[1]);
			
			if(y>0 && data[y-1][x]=='.'){ data[y-1][x] = '*'; set.add(y-1+","+x); }
			if(y<data.length-1 && data[y+1][x]=='.'){ data[y+1][x] = '*'; set.add(y+1+","+x); }
			if(x>0 && data[y][x-1]=='.'){ data[y][x-1] = '*'; set.add(y+","+(x-1)); }
			if(x<data[0].length-1 && data[y][x+1]=='.'){ data[y][x+1] = '*'; set.add(y+","+(x+1)); }
		}
		//沒有找到任何後序可行的策略
		if(set.isEmpty()) return -1;
		int r = f(data, set, goal);
		if(r<0) return -1;
		return r + 1;
	}
	
	public static void main(String[] args){
		Scanner scan = new Scanner(System.in);
		
		String[] ss = scan.nextLine().trim().split(" +");
		int n = Integer.parseInt(ss[0]);
		int m = Integer.parseInt(ss[1]);
		
		char[][] data = new char[n][];
		for(int i=0; i<n; i++){
			data[i] = scan.nextLine().trim().toCharArray();
		}
		
		Set set = new HashSet();
		set.add("0,0");
		System.out.println(f(data, set, n-1 + "," + (m-1)));
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章