目錄
1.馬踏棋盤算法介紹和遊戲演示
1)馬踏棋盤算法也被稱爲騎士周遊問題
2)將馬隨機放在國際象棋的8X8棋盤Board[0~ 7][0~7]的某個方格中,馬按走棋規則(馬走日字)進行移動。要求每個方格只進入一次,走遍棋盤上全部64個方格
3) 遊戲演示:http://www.4399.com/flash/146267_2.htm
2.馬踏棋盤遊戲代碼實現
1)馬踏棋盤問題(騎士周遊問題)實際上是圖的深度,優先搜索(DFS)的應用。
2)如果使用回溯(就是深度優先搜索)來解決,假如馬兒踏了53個點,如圖:走到了第53個,座標(1,0) ,發現已經走到盡頭,沒辦法,那就只能回退了,查看其他的路徑,就在棋盤.上不停的回溯
3) 分析第一種方式的問題,並使用貪心算法( greedyalgorithm)進行優化。解決馬踏棋盤問題.
4)使用前面的遊戲來驗證算法是否正確。
3.騎士周遊問題的解決步驟和思路
1.創建棋盤chessBoard,是一個二維數組
2.將當前位置設置爲已經訪問,然後根據當前位置,計算馬兒還能走哪些位置,並放入到一個集合中(ArrayList),最多有8個位置,每走一步, 就使用step+1
3.遍歷ArrayList中存放的所有位置,看看哪個可以走通,如果走通,就繼續,走不通,就回溯
4.判斷馬兒是否完成了任務,使用step 和應該走的步數比較,如果沒有達到數量,則表示沒有完成任務,將整個棋盤置0
注意:馬兒不同的走法(策略),會得到不同的結果,效率也會有影響(優化)
4.代碼優化
使用該代碼,我本地沒有跑出結果,一直在運行,所以對代碼進行下一步優化。
等了好久都木有結果:
由於馬兒的不同走法會有不同的策略,如果回溯的話,是比較影響性能的,所有,我們在對馬兒走下一步選擇的點可以進行優化。
我們可以算出馬兒選擇走下一步的下一步有幾種選擇,使用貪心算法,算出最少選擇進行下一步,下一步的下一步選擇越少,則回溯所消耗的性能越少,所以,我們可以對下一步集合中的點進行排序,選出選擇最少的。
優化前沒有跑出結果,但是優化後:
通過結果玩遊戲,完美win,但是不一定每次都能回到原點:
5.代碼實現
package com.example.datastructureandalgorithm.horse;
import java.awt.*;
import java.util.ArrayList;
import java.util.Comparator;
/**
* 馬踏棋盤算法
*
* @author 浪子傑
* @version 1.0
* @date 2020/6/27
*/
public class HorseChessDemo {
/**
* 棋盤的行數
*/
private static int X;
/**
* 棋盤的列數
*/
private static int Y;
/**
* 標記棋盤各個位置是否被訪問
*/
private static boolean visited[];
/**
* 判斷是否成功
*/
private static boolean isFinished;
public static void main(String[] args) {
System.out.println("騎士開始周遊啦...");
X = 6;
Y = 6;
// 初始位置行數
int row = 1;
// 初始位置列數
int column = 2;
// 創建棋盤
int[][] chessboard = new int[X][Y];
visited = new boolean[X * Y];
// 耗時
long start = System.currentTimeMillis();
traversalChess(chessboard, row - 1, column - 1, 1);
long end = System.currentTimeMillis();
System.out.println("總共耗時:" + (end - start) + "毫秒");
for (int[] rows : chessboard) {
for (int step : rows) {
System.out.print(step + "\t");
}
System.out.println();
}
}
public static void traversalChess(int[][] chessboard, int row, int column, int step) {
chessboard[row][column] = step;
// row * X + column表示被訪問節點的位置,即從0開始數
visited[row * X + column] = true;
// 獲取下一步可以走的位置的集合
ArrayList<Point> arrayList = next(new Point(column, row));
// 排序
sort(arrayList);
while (!arrayList.isEmpty()) {
Point point = arrayList.remove(0);
// 判斷是否被訪問過
if (!visited[point.y * X + point.x]) {
// 記得step+1,表示一共走的步數
traversalChess(chessboard, point.y, point.x, step + 1);
}
}
// 判斷馬兒是否完成了任務,使用step和棋盤總步數進行比較
// 如果沒有完成,則將棋盤還原
if (step < X * Y && !isFinished) {
chessboard[row][column] = 0;
visited[row * X + column] = false;
} else {
isFinished = true;
}
}
/**
* 根據當前的位置,計算馬兒還可以走哪些位置,並放入list中,list最大爲8
*
* @param point
* @return
*/
public static ArrayList<Point> next(Point point) {
ArrayList<Point> arrayList = new ArrayList<>();
Point p1 = new Point();
// 表示馬兒可以走上圖中的位置1
if ((p1.x = point.x - 1) >= 0 && (p1.y = point.y - 2) >= 0) {
arrayList.add(new Point(p1));
}
// 表示馬兒可以走上圖中的位置2
if ((p1.x = point.x + 1) < X && (p1.y = point.y - 2) >= 0) {
arrayList.add(new Point(p1));
}
// 表示馬兒可以走上圖中的位置3
if ((p1.x = point.x + 2) < X && (p1.y = point.y - 1) >= 0) {
arrayList.add(new Point(p1));
}
// 表示馬兒可以走上圖中的位置4
if ((p1.x = point.x + 2) < X && (p1.y = point.y + 1) < Y) {
arrayList.add(new Point(p1));
}
// 表示馬兒可以走上圖中的位置5
if ((p1.x = point.x + 1) < X && (p1.y = point.y + 2) < Y) {
arrayList.add(new Point(p1));
}
// 表示馬兒可以走上圖中的位置6
if ((p1.x = point.x - 1) >= 0 && (p1.y = point.y + 2) < Y) {
arrayList.add(new Point(p1));
}
// 表示馬兒可以走上圖中的位置7
if ((p1.x = point.x - 2) >= 0 && (p1.y = point.y + 1) < Y) {
arrayList.add(new Point(p1));
}
// 表示馬兒可以走上圖中的位置8
if ((p1.x = point.x - 2) >= 0 && (p1.y = point.y - 1) >= 0) {
arrayList.add(new Point(p1));
}
return arrayList;
}
/**
* 對list進行排序
* @param arrayList
*/
public static void sort(ArrayList<Point> arrayList) {
arrayList.sort(new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
int count1 = next(o1).size();
int count2 = next(o2).size();
return count1 - count2;
}
});
}
}