[英]Determining if a knight can pass through all cells in a 2d array - if so print board
我需要關於這個稱為“騎士路徑”的問題的建議。 給定一個 n*n 板,其單元格初始化為 0,我需要確定,給定任意騎士的 position,騎士是否可以恰好通過板上的每個單元格一次,騎士訪問過的每個單元格都將被標記為計數器,從 1 - n^2 開始計數。 如果有可能,我需要打印電路板。 我需要打印所有有效的電路板。 對於那些不了解國際象棋規則的人來說,馬可以垂直上下移動一格,水平移動兩格,或者垂直移動兩格,水平移動一格。
例如,給定一塊 5*5 的板,從 (0,0) 開始,該方法應打印:
{{1,16,11,6,21},
{10,5,20,15,12},
{17,2,13,22,7},
{4,9,24,19,14},
{25,18,3,8,23}};
上面的輸出將是少數輸出之一,因為考慮不同的初始位置可能有不同的其他方法。 我寫了下面的代碼,但它沒有打印任何東西。 我需要找出這里的邏輯缺陷,這樣我才能讓它發揮作用。
public class KnightDemo {
static int counter = 1;
public static void KnightPath(int[][] b, int i, int j) {
b[i][j] = counter;
if (counter == b.length * b[0].length) {
printMatrix(b);
return;
} else {
counter++;
if (isValid(b, i - 1, j + 2) && b[i - 1][j + 2] == 0) {
KnightPath(b, i - 1, j + 2);
} else {
return;
}
if (isValid(b, i - 2, j + 1) && b[i - 1][j + 1] == 0) {
KnightPath(b, i - 2, j + 1);
} else {
return;
}
if (isValid(b, i - 1, j - 2) && b[i - 1][j - 2] == 0) {
KnightPath(b, i - 1, j - 2);
} else {
return;
}
if (isValid(b, i - 2, j - 1) && b[i - 2][j - 1] == 0) {
KnightPath(b, i - 2, j - 1);
} else {
return;
}
if (isValid(b, i + 2, j - 1) && b[i + 2][j - 1] == 0) {
KnightPath(b, i + 2, j - 1);
} else {
return;
}
if (isValid(b, i + 1, j - 2) && b[i + 1][j - 2] == 0) {
KnightPath(b, i + 1, j - 2);
} else {
return;
}
if (isValid(b, i + 1, j + 2) && b[i + 1][j + 2] == 0) {
KnightPath(b, i + 1, j + 2);
} else {
return;
}
if (isValid(b, i + 2, j + 1) && b[i + 2][j + 1] == 0) {
KnightPath(b, i + 2, j + 1);
} else {
return;
}
}
}
public static boolean isValid(int[][] a, int i, int j) {
if (i > a.length - 1 || i < 0 || j > a[0].length - 1 || j < 0) {
return false;
}
return true;
}
public static void main(String[] args) {
int[][] b = new int[5][5];
for (int i = 0; i < b.length; i++) {
for (int j = 0; j < b[0].length; j++) {
KnightPath(b, i, j);
}
}
}
public static void printMatrix(int[][] matrix) {
for (int[] rows: matrix) {
StringBuilder buff = new StringBuilder();
buff.append("[");
for (int i = 0; i < rows.length; i++) {
int value = rows[i];
buff.append(value);
if (i < rows.length - 1) {
buff.append(", ");
}
}
buff.append("]");
System.out.println(buff.toString());
}
}
}
output 是
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
[11, 12, 13, 14, 15]
[16, 17, 18, 19, 20]
[21, 22, 23, 24, 25]
根據 OP 在評論部分的解釋,目標是 map 出騎士可以從棋盤上的某個位置走的所有可能路徑。 基本上,給定騎士的位置b[i][j]
,計算所有合法路徑。
如果馬在 {0, 0},則馬只有兩條合法路徑以 {1, 2} 和 {2, 1} 結束。 這里的想法是在 map 中捕獲它。然后,移動到板上的下一個位置(即 {1, 0})並重復該過程。 由於每個電路板位置都可以標識為 integer( counter
),我們可以將其用於 map 路徑...
0=[{1, 2}, {2, 1}]
1=[{2, 2}, {1, 3}, {2, 0}]
...
n=[{n^-2 - 3, n^-2 - 2}, {n^-2 - 2, n^-2 - 3}] // last location is always a corner
為了簡單起見,我決定創建一個 Java 坐標record
來存儲給定路徑結束位置的 { x, y } 坐標,使我的 map <Integer, Set<Coordinates>>
這里的邏輯很簡單。 首先,為 map 播種矩陣中每個對應位置的空列表。 然后,遍歷矩陣(二維數組)並計算騎士可以從該位置走的所有合法路徑。 對於每條合法路徑,添加路徑結束位置的Coordinates
。 我使用了一個Set
來消除重復的坐標。
我的解決方案(可能不是最優的)如下(使用 OP 代碼作為基線)- 需要 Java 15 或更高版本才能運行。 對於 Java 14 或更早版本,將Coordinates
替換為長度為 2 的Integer[]
,並將坐標存儲在其中。
public class KnightDemo {
static int counter = 0;
static Map<Integer, Set<Coordinates>> map = new HashMap<>();
public static void KnightPath(int[][] b, int i, int j) {
Set<Coordinates> paths = map.get(counter);
if (isValid(b, i - 1, j + 2)) {
paths.add(new Coordinates(i - 1, j + 2));
map.put(counter, paths);
}
if (isValid(b, i - 2, j + 1)) {
paths.add(new Coordinates(i - 2, j + 1));
map.put(counter, paths);
}
if (isValid(b, i - 1, j - 2)) {
paths.add(new Coordinates(i - 1, j - 2));
map.put(counter, paths);
}
if (isValid(b, i - 2, j - 1)) {
paths.add(new Coordinates(i - 2, j - 1));
map.put(counter, paths);
}
if (isValid(b, i + 2, j - 1)) {
paths.add(new Coordinates(i + 2, j - 1));
map.put(counter, paths);
}
if (isValid(b, i + 1, j - 2)) {
paths.add(new Coordinates(i + 1, j - 2));
map.put(counter, paths);
}
if (isValid(b, i + 1, j + 2)) {
paths.add(new Coordinates(i + 1, j + 2));
map.put(counter, paths);
}
if (isValid(b, i + 2, j + 1)) {
paths.add(new Coordinates(i + 2, j + 1));
map.put(counter, paths);
}
counter++;
}
public static boolean isValid(int[][] a, int i, int j) {
return i >= 0 && i < a.length && j >= 0 && j < a[0].length;
}
public static void main(String[] args) {
int[][] b = new int[5][5];
for (int i = 0; i < b.length; i++) {
for (int j = 0; j < b[0].length; j++) {
map.put(counter, new HashSet<>()); // add a new set before calculating paths
KnightPath(b, i, j);
}
}
map.entrySet().stream().forEach(System.out::println);
}
private static record Coordinates(int row, int col) {
@Override
public String toString() {
return "{" + row + ", " + col + "}";
}
}
}
程序輸出:
0=[{1, 2}, {2, 1}]
1=[{2, 2}, {1, 3}, {2, 0}]
2=[{2, 3}, {1, 4}, {2, 1}, {1, 0}]
3=[{2, 2}, {1, 1}, {2, 4}]
4=[{2, 3}, {1, 2}]
5=[{2, 2}, {0, 2}, {3, 1}]
6=[{2, 3}, {0, 3}, {3, 0}, {3, 2}]
7=[{0, 0}, {3, 3}, {2, 4}, {0, 4}, {3, 1}, {2, 0}]
8=[{0, 1}, {3, 4}, {3, 2}, {2, 1}]
9=[{3, 3}, {2, 2}, {0, 2}]
10=[{1, 2}, {0, 1}, {4, 1}, {3, 2}]
11=[{0, 0}, {3, 3}, {1, 3}, {0, 2}, {4, 0}, {4, 2}]
12=[{0, 1}, {3, 4}, {1, 4}, {0, 3}, {4, 1}, {3, 0}, {1, 0}, {4, 3}]
13=[{1, 1}, {4, 4}, {0, 2}, {0, 4}, {4, 2}, {3, 1}]
14=[{1, 2}, {0, 3}, {4, 3}, {3, 2}]
15=[{2, 2}, {1, 1}, {4, 2}]
16=[{2, 3}, {1, 2}, {1, 0}, {4, 3}]
17=[{1, 1}, {4, 4}, {2, 4}, {1, 3}, {4, 0}, {2, 0}]
18=[{1, 2}, {1, 4}, {4, 1}, {2, 1}]
19=[{2, 2}, {1, 3}, {4, 2}]
20=[{3, 2}, {2, 1}]
21=[{3, 3}, {2, 2}, {2, 0}]
22=[{3, 4}, {2, 3}, {3, 0}, {2, 1}]
23=[{2, 2}, {2, 4}, {3, 1}]
24=[{2, 3}, {3, 2}]
是的你可以! 假設您用black
和white
為矩陣播種。 您可以增強邏輯,以便如果結束位置對應於您的顏色,則您不會將其添加為有效路徑,因為它被您的一個作品擋住了。
Coordinate
object 作為鍵public class KnightDemo {
static int counter = 0;
static Map<Coordinates, Set<Coordinates>> map = new HashMap<>();
public static void KnightPath(int[][] b, Coordinates coordinates) {
Set<Coordinates> paths = map.get(coordinates);
if (isValid(b, coordinates.row() - 1, coordinates.col() + 2)) {
paths.add(new Coordinates(coordinates.row() - 1, coordinates.col() + 2));
map.put(coordinates, paths);
}
if (isValid(b, coordinates.row() - 2, coordinates.col() + 1)) {
paths.add(new Coordinates(coordinates.row() - 2, coordinates.col() + 1));
map.put(coordinates, paths);
}
if (isValid(b, coordinates.row() - 1, coordinates.col() - 2)) {
paths.add(new Coordinates(coordinates.row() - 1, coordinates.col() - 2));
map.put(coordinates, paths);
}
if (isValid(b, coordinates.row() - 2, coordinates.col() - 1)) {
paths.add(new Coordinates(coordinates.row() - 2, coordinates.col() - 1));
map.put(coordinates, paths);
}
if (isValid(b, coordinates.row() + 2, coordinates.col() - 1)) {
paths.add(new Coordinates(coordinates.row() + 2, coordinates.col() - 1));
map.put(coordinates, paths);
}
if (isValid(b, coordinates.row() + 1, coordinates.col() - 2)) {
paths.add(new Coordinates(coordinates.row() + 1, coordinates.col() - 2));
map.put(coordinates, paths);
}
if (isValid(b, coordinates.row() + 1, coordinates.col() + 2)) {
paths.add(new Coordinates(coordinates.row() + 1, coordinates.col() + 2));
map.put(coordinates, paths);
}
if (isValid(b, coordinates.row() + 2, coordinates.col() + 1)) {
paths.add(new Coordinates(coordinates.row() + 2, coordinates.col() + 1));
map.put(coordinates, paths);
}
}
public static boolean isValid(int[][] a, int i, int j) {
return i >= 0 && i < a.length && j >= 0 && j < a[0].length;
}
public static void main(String[] args) {
int[][] b = new int[5][5];
for (int i = 0; i < b.length; i++) {
for (int j = 0; j < b[0].length; j++) {
Coordinates coordinates = new Coordinates(i, j);
map.put(coordinates, new HashSet<>());
KnightPath(b, coordinates);
counter++;
}
}
map.entrySet().stream().forEach(System.out::println);
}
private static record Coordinates(int row, int col) {
@Override
public String toString() {
return "{" + row + ", " + col + "}";
}
}
}
輸出:
{0, 0}=[{1, 2}, {2, 1}]
{2, 2}=[{0, 1}, {3, 4}, {1, 4}, {0, 3}, {4, 1}, {3, 0}, {1, 0}, {4, 3}]
{4, 4}=[{2, 3}, {3, 2}]
{0, 1}=[{2, 2}, {1, 3}, {2, 0}]
{2, 3}=[{1, 1}, {4, 4}, {0, 2}, {0, 4}, {4, 2}, {3, 1}]
{0, 2}=[{2, 3}, {1, 4}, {2, 1}, {1, 0}]
{2, 4}=[{1, 2}, {0, 3}, {4, 3}, {3, 2}]
{0, 3}=[{2, 2}, {1, 1}, {2, 4}]
{0, 4}=[{2, 3}, {1, 2}]
{3, 0}=[{2, 2}, {1, 1}, {4, 2}]
{3, 1}=[{2, 3}, {1, 2}, {1, 0}, {4, 3}]
{1, 0}=[{2, 2}, {0, 2}, {3, 1}]
{3, 2}=[{1, 1}, {4, 4}, {2, 4}, {1, 3}, {4, 0}, {2, 0}]
{1, 1}=[{2, 3}, {0, 3}, {3, 0}, {3, 2}]
{3, 3}=[{1, 2}, {1, 4}, {4, 1}, {2, 1}]
{1, 2}=[{0, 0}, {3, 3}, {2, 4}, {0, 4}, {3, 1}, {2, 0}]
{3, 4}=[{2, 2}, {1, 3}, {4, 2}]
{1, 3}=[{0, 1}, {3, 4}, {3, 2}, {2, 1}]
{1, 4}=[{3, 3}, {2, 2}, {0, 2}]
{4, 0}=[{3, 2}, {2, 1}]
{4, 1}=[{3, 3}, {2, 2}, {2, 0}]
{2, 0}=[{1, 2}, {0, 1}, {4, 1}, {3, 2}]
{4, 2}=[{3, 4}, {2, 3}, {3, 0}, {2, 1}]
{2, 1}=[{0, 0}, {3, 3}, {1, 3}, {0, 2}, {4, 0}, {4, 2}]
{4, 3}=[{2, 2}, {2, 4}, {3, 1}]
它們的打印順序不同,但您可以看出坐標{2, 2}
與上一個示例中的counter==12
是同一組。 單元格 {2, 2} 是從左上角算起的第 13 個單元格。
要解決所有路徑,您需要重置已用盡的路徑的放置值,以便新路徑可以訪問它們。 此外,你的計數器應該反映你走了多深,這樣如果你退出嘗試另一條路徑,你的計數器也應該回滾。 我建議將計數器作為參數傳遞,而不是使用 static 計數器。 另外,如果你想嘗試所有有效的可能性,那么只要一種可能性被認為無效,你就需要避免那些 return 語句。
public static void KnightPath(int[][] b, int i, int j, int counter) {
...
if (isValid(b, i - 1, j + 2) && b[i - 1][j + 2] == 0) {
KnightPath(b, i - 1, j + 2, counter+1);
}
...
b[i][j] = 0;
}
public static void main(String[] args) {
...
KnightPath(b, i, j, 1);
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.