2-4 马的Hamilton周游路线问题
问题描述
8*8的国际象棋棋盘上的一只马,恰好走过除起点外的其他63个位置各一次,最后回到起点,这条路线称为马的一条Hamilton周游路线。对于给定的m*n的国际象棋棋盘,m和n均为大于5的偶数,且|m-n|≤2,试设计一个分治算法找出马的一条Hamilton周游路线。
回溯法
Java
public class Main {
private static int max = 101;
private static int[][] board = new int[max][max];
private static int startX, startY;
private static int[] dx = {-2, -1, 1, 2, -2, -1, 2, 1};
private static int[] dy = {-1, -2, -2, -1, 1, 2, 1, 2};
private static int m = 8;//行
private static int n = 6;//列
public static void main(String[] args) {
startX = 2;
startY = 2;
int number = 1;
board[startX][startY] = 1;
backtrack(startX, startY, number);
}
private static void backtrack(int x, int y, int num) {
//已经走完棋盘中所有的点
if (num == n * m && isNextStepStartPoint(x, y)) {
print(n, m);
System.exit(1);
}
//表示每一个格都有八种走法
for (int i = 0; i < 8; i++) {
int nextX = x + dx[i];
int nextY = y + dy[i];
if (isNextStepOk(nextX, nextY)) {
//走到下一个位置,设置其序号为 number+1
board[nextX][nextY] = num + 1;
backtrack(nextX, nextY, num + 1);
//回溯
board[nextX][nextY] = 0;
}
}
}
//判断下一步是否回到起点
private static boolean isNextStepStartPoint(int x, int y) {
for (int i = 0; i < 8; i++) {
if (x + dx[i] == startX && y + dy[i] == startY)
return true;
}
return false;
}
private static void print(int n, int m) {
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++)
System.out.print(String.format("%4d", board[i][j]));
System.out.println();
}
if(board[1][1] != 1){
System.out.println("-------Change to start from (1,1)--------");
int tmpStart = board[1][1];
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
if(board[i][j] > tmpStart)
board[i][j] = board[i][j]-tmpStart+1;
else if(board[i][j] < tmpStart)
board[i][j] = board[i][j]+m*n-tmpStart+1;
else
board[i][j] = 1;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++)
System.out.print(String.format("%4d", board[i][j]));
System.out.println();
}
}
//参数x,y 表示棋盘的位置
//检测(x,y) 对应位置在棋盘中是否合法
private static boolean isNextStepOk(int x, int y) {
if (x < 1 || y < 1 || x > m || y > n || board[x][y] != 0)
return false;
else
return true;
}
}
Output
7 4 19 48 21 44
18 1 6 45 34 47
5 8 3 20 43 22
2 17 10 33 46 35
9 14 27 36 23 42
28 11 16 39 32 37
15 26 13 30 41 24
12 29 40 25 38 31
-------Change to start from (1,1)--------
1 46 13 42 15 38
12 43 48 39 28 41
47 2 45 14 37 16
44 11 4 27 40 29
3 8 21 30 17 36
22 5 10 33 26 31
9 20 7 24 35 18
6 23 34 19 32 25
队列
Java
import java.util.LinkedList;
import java.util.Queue;
class Point{
int x;
int y;
}
public class Main {
private static int max = 101;
private static int[][] board = new int[max][max];//下标从1开始
private static int startX, startY;
private static int[] dx = {-2, -1, 1, 2, -2, -1, 2, 1};
private static int[] dy = {-1, -2, -2, -1, 1, 2, 1, 2};
private static int m = 8;//行
private static int n = 6;//列
public static void main(String[] args) {
startX = 2;
startY = 2;
int number = 1;
board[startX][startY] = 1;
backtrack(startX, startY, number);
}
private static void backtrack(int x, int y, int num) {
//已经走完棋盘中所有的点
if (num == n * m && isNextStepStartPoint(x, y)) {
print(n, m);
System.exit(1);
}else {
Queue<Point> pointQueue = new LinkedList<>();
int minStep = 8;
for(int i=0; i<8; i++){
int pointX = x + dx[i];
int pointY = y + dy[i];
if(isNextStepOk(pointX, pointY)){
Point t = new Point();
t.x = pointX;
t.y = pointY;
int tmpStep = nextPossibleSteps(pointX, pointY);
if(tmpStep <= minStep)
{
minStep = tmpStep;
// ((LinkedList<Point>) pointQueue).add(0, t);
((LinkedList<Point>) pointQueue).addFirst(t);
}else
pointQueue.add(t);
}
}
while(!pointQueue.isEmpty()){
Point point = pointQueue.poll();
board[point.x][point.y] = num+1;
backtrack(point.x, point.y, num+1);
board[point.x][point.y] = 0;
}
}
}
//判断下一步是否回到起点
private static boolean isNextStepStartPoint(int x, int y) {
for (int i = 0; i < 8; i++) {
if (x + dx[i] == startX && y + dy[i] == startY)
return true;
}
return false;
}
private static void print(int n, int m) {
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++)
System.out.print(String.format("%4d", board[i][j]));
System.out.println();
}
if(board[1][1] != 1){
System.out.println("-------Change to start from (1,1)--------");
int tmpStart = board[1][1];
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
if(board[i][j] > tmpStart)
board[i][j] = board[i][j]-tmpStart+1;
else if(board[i][j] < tmpStart)
board[i][j] = board[i][j]+m*n-tmpStart+1;
else
board[i][j] = 1;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++)
System.out.print(String.format("%4d", board[i][j]));
System.out.println();
}
}
//参数x,y 表示棋盘的位置
//检测(x,y) 对应位置在棋盘中是否合法
private static boolean isNextStepOk(int x, int y) {
if (x < 1 || y < 1 || x > m || y > n || board[x][y] != 0)
return false;
else
return true;
}
//该处有效的下一步有多少种
private static int nextPossibleSteps(int x, int y){
int steps = 0;
for(int i=0; i<8; i++){
if(isNextStepOk(x+dx[i], y+dy[i]))
steps++;
}
return steps;
}
}
Output
37 22 13 2 35 24
12 1 36 23 14 3
21 38 11 48 25 34
10 45 32 39 4 15
31 20 47 16 33 26
46 9 44 27 40 5
19 30 7 42 17 28
8 43 18 29 6 41
-------Change to start from (1,1)--------
1 34 25 14 47 36
24 13 48 35 26 15
33 2 23 12 37 46
22 9 44 3 16 27
43 32 11 28 45 38
10 21 8 39 4 17
31 42 19 6 29 40
20 7 30 41 18 5
优先队列
Java
import java.util.Comparator;
import java.util.PriorityQueue;
class Point{
int x;
int y;
int nextPossibleSteps;//表示当前点的下一位置有多少种走法;走法少的优先考虑
int currentToMidLength;//表示当前点与中心点的距离;距离中心点远的优先考虑
}
//class Point implements Comparable {
// int x;
// int y;
// int nextPossibleSteps;//表示当前点的下一位置有多少种走法;走法少的优先考虑
// int currentToMidLength;//表示当前点与中心点的距离;距离中心点远的优先考虑
//
// public int compareTo(Object o) {
// Point point=(Point) o;
// int result = Integer.compare(nextPossibleSteps, point.nextPossibleSteps);//先按 下次可能步数 由小到大 排列
// if(result == 0){
// result = Integer.compare(point.currentToMidLength, currentToMidLength);//下次可能步数 相同时,再按 与中心点距离 由大到小 排列
// }
// return result;
// }
//
//}
public class Main {
private static int max = 101;
private static int[][] board = new int[max][max];
private static int startX, startY;
private static