一個7*8的數組模擬迷宮,障礙用1表示,通路使用0表示,給定起點(1,1)和終點(6,5),要求給出起點到終點的通路java
/** * 建立一個二維數組,用於模擬8*7迷宮 * 使用1表示不可經過的實心方塊,0表示可經過磚塊 * (6,5)爲默認終點,(1,1)爲默認起點 * @return */ public static int[][] getMap(){ int[][] map = new int[8][7]; //上下全置爲1 for(int i = 0;i <7 ;i++){ map[0][i] = 1; map[7][i] = 1; } //左右全置爲1 for(int i = 0;i < 8;i++){ map[i][0] = 1; map[i][6] = 1; } //設置擋板 map[3][1] = 1; map[3][2] = 1; //輸出地圖 System.out.println("地圖的初始狀況:"); showMap(map); return map; } /** * 展現地圖 * @param map */ public static void showMap(int[][] map) { for(int i = 0;i < 8;i++){ for(int j = 0;j < 7;j++){ System.out.print(map[i][j] + " "); } System.out.println(); } }
對於這個尋路程序,咱們能夠看見,往四個方向走的過程實際上除了方向外動做上是同樣的;而具體分析同一個方向,每走過一個座標的動做也是同樣的,咱們對流程進行分析:算法
int[x][y]==1
)表現爲代碼實際上就是一個遞歸的過程:數組
/** * 給定起始點,根據地圖找路 * 使用2表示能夠走通的路,使用3表示走過可是不通的路 * @param map 地圖二維數組 * @param x 起始點橫座標 * @param y 起始點縱座標 * @return */ public static boolean findWay(int[][] map, int x, int y) { //若是走到了終點就終止 if (map[6][5] == 2){ return true; }else { //只有爲0的路才能經過 if (map[y][x] == 0) { //若是該點能夠走通就打上標記 map[y][x] = 2; if (findWay(map, x, y + 1)) { //向下遞歸 return true; } else if (findWay(map, x + 1, y)) { //向右遞歸 return true; } else if (findWay(map, x, y - 1)) { //向上遞歸 return true; } else if (findWay(map, x - 1, y)) { //向左遞歸 return true; } else { //都走不通說明是死衚衕 map[y][x] = 3; return false; } }else { //不爲0說明要麼是死路要麼是障礙 return false; } } }
將findWay()
方法中的終止條件從map[6][5] == 2
換成其餘座標便可更換終點位置,3d
棋盤大小和障礙物位置不影響findWay()
方法尋路。code
皇后問題,一個古老而著名的問題,是回溯算法的典型案例。該問題由國際西洋棋棋手馬克斯·貝瑟爾於 1848 年提出:blog
在 8×8 格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,求有多少種擺法?遞歸
首先,咱們先使用一個長度爲8數組來表示八皇后的擺放位置,數組下標+1即表示棋盤的第幾行,數組下標對應的存放的數字+1即爲棋盤的第幾列。舉個例子:ip
arr = {0,2,3,8,4,6,2,7}get
其中,元素0下標爲0,即表示第一行第一列;元素2下標爲1,即表示第二行第三列......以此類推。io
任意假設任意座標分標爲(x1,y1),(x2,y2)
,也就是用數組表示爲arr[x1]=y1,arr[x2]=y2
的兩個皇后不容許在同一列,咱們能夠理解爲:
arr[x1] != arr[x2]
;
而任意座標的皇后不容許在同一斜線,即(x2-x1)=(y2-y1)
,也就是斜率不該當相同,咱們能夠理解爲:
Math.abs(x2-x1) != Math.abs(arr[x2]-arr[x1])
(注:Math.abs()
爲求絕對值方法)
在前面明確瞭如何用數組表示位置,以及如何檢查皇后是否容許擺放後,咱們有以下代碼:
//表示皇后位置的數組 int[] arr = new int[8]; /** * 檢查第n個皇后是否與前面擺放的皇后衝突 * @param n * @return */ public boolean check(int n) { //檢查第n層以前的皇后位置 for (int i = 0; i < n; i++) { // arr[i] == arr[n] 檢查是否同一列 // Math.abs(n - i) == Math.abs(arr[n] - arr[i]) 檢查是否同一斜線 if (arr[i] == arr[n] || Math.abs(n - i) == Math.abs(arr[n] - arr[i])) { return false; } } return true; }
接着咱們須要考慮如何使用遞歸方法來作到如下效果:
使用一個方法遍歷第n行的每一列,檢查每一列是否能夠放置皇后:
最終代碼實現結果以下:
/** * @Author:黃成興 * @Date:2020-06-26 20:53 * @Description:八皇后問題 */ public class EightQueens { public static void main(String[] args) { EightQueens eightQueens = new EightQueens(); eightQueens.set(0); System.out.println("共有擺法:" + eightQueens.count); } //記錄八皇后有幾種擺法 int count = 0; //表示皇后位置的數組 int[] arr = new int[8]; /** * 擺放皇后 * @param n 第幾個皇后 */ private void set(int n) { //若是放置好了第8個皇后 if (n == 8){ show(); //記錄一種擺放方式 count++; //回到第一層繼續遞歸 return; } //遍歷第n行的每一列 for (int i = 0; i < 8; i++) { //將該皇后放置在第n行第i列 arr[n] = i; //檢查放置位置是否合適 if (check(n)){ //若是位置合適,就遞歸找下一個(n+1)皇后的擺放位置 set(n + 1); } //若是位置不合適,就跳過這一列檢查下一列 } } /** * 檢查第n個皇后是否與前面擺放的皇后衝突 * @param n * @return */ public boolean check(int n) { //檢查第n層以前的皇后位置 for (int i = 0; i < n; i++) { // arr[i] == arr[n] 檢查是否同一列 // Math.abs(n - i) == Math.abs(arr[n] - arr[i]) 檢查是否同一斜線 if (arr[i] == arr[n] || Math.abs(n - i) == Math.abs(arr[n] - arr[i])) { return false; } } return true; } /** * 展現某一擺法中八皇后的擺放位置 */ public void show() { for (int i : arr) { System.out.print(i + " "); } System.out.println(); } }