- 代碼比較少,幾乎一比一的註釋,可以多看兩遍,debug試試。
public class Solution0812 {
public static void main(String[] args) {
Solution0812 solution = new Solution0812();
solution.eightQueen(8);
}
private int count = 0;
private void eightQueen(int n) {
//初始化,所有的格子填充一個點
char[][] queen = new char[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
queen[i][j] = '.';
}
}
//從第0行開始安排 Queen 的擺放位置
backtrack(queen, 0, n);
}
private void backtrack(char[][] queen, int i, int n) {
if (i == n) {
//已經進行到第n行,則表示滿足規則,棋盤已經列舉完畢,進行棋盤打印,並返回
count++;
System.out.println("第" + count + " 種可能: " + Arrays.deepToString(queen));
return;
}
//j是列數,表示預計在【i,j】放上下一個 Queen
for (int j = 0; j < n; j++) {
//判斷在【i,j】放一個 Queen ,是否有效可行,如果不可行,則 j++,換下一列試試
if (!judge(queen, i, j)) continue;
//如果可行,則在【i,j】處放一個 Queen
queen[i][j] = 'Q';
//繼續進行下一行 Queen 的位置擺放,因爲在這一行肯定只能放一個 Queue
backtrack(queen, i + 1, n);
//如果棋盤全部擺放結束,或者嘗試在第【i + 1,j】,j 從0-n (前閉後開)擺放Queue,都不可行
//則需要進行回溯,即第i行的 Queen 需要換一個位置擺放
//回溯,將【i,j】的Queen還原爲'.',遍歷嘗試在【i,j+1】位置擺放一個Queen
//回溯的本質是枚舉所有可能情況(並進行適當剪枝,去掉不可能的路徑,返回上一步,繼續枚舉)
queen[i][j] = '.';
}
}
/**
* 判斷在【i,j】放一個queen,是否有效可行
*/
private boolean judge(char[][] queen, int i, int j) {
//在 i 這一行只能放一個 Queen ,之前已經做過處理
//在 j 這一列只能放一個 Queen ,如果檢測到這一列有 Queen ,則不可行,返回false
for (int k = 0; k < i; k++) {
if (queen[k][j] == 'Q')
return false;
}
//比較斜對角
//往左上角方向延伸,如果檢測到這一條對角線有 Queen ,則不可行,返回false
for (int z = i - 1, k = j - 1; z >= 0 && k >= 0; z--, k--) {
if (queen[z][k] == 'Q') return false;
}
//往右上角方向延伸,如果檢測到這一條對角線有 Queen ,則不可行,返回false
for (int z = i - 1, k = j + 1; z >=0 && k < queen.length; z--, k++) {
if (queen[z][k] == 'Q') return false;
}
//行、列、對角線都匹配完成,返回true,表示【i,j】處可以放置一 個Queen
return true;
}
}
輸出結果:
總共92種解法