2n皇后
問題描述:
給定一個n*n的棋盤,棋盤中有一些位置不能放皇后。現在要向棋盤中放入n個黑皇后和n個白皇后,使任意的兩個黑皇后都不在同一行、同一列或同一條對角線上,任意的兩個白皇后都不在同一行、同一列或同一條對角線上。問總共有多少种放法?n小於等於8。
輸入格式:
輸入的第一行爲一個整數n,表示棋盤的大小。
接下來n行,每行n個0或1的整數,如果一個整數爲1,表示對應的位置可以放皇后,如果一個整數爲0,表示對應的位置不可以放皇后。
輸出格式
輸出一個整數,表示總共有多少种放法。
樣例輸入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
樣例輸出
2
樣例輸入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
樣例輸出
0
相比於前幾道dfs的算法題,這道就是比較難,本身的選擇就很難,況且這不是八皇后,只放黑皇后的問題,這是黑白皇后一起放的問題。(這個黑白問題一起放只需該一行代碼,很巧妙)
import java.util.Scanner;
/**
* @author sjf
* @date 2020/3/3 11:56
*/
public class dfs_2n_queen {
static int n; //棋盤的大小
static int[][] map = new int[8][8]; //棋盤存儲
static int ans;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
//刻畫棋盤
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
map[i][j] = sc.nextInt();
}
}
dfs(0,6);
System.out.println(ans);
}
//逐行遍歷
public static void dfs(int x,int queen) {
if (x == n) {
if(queen==6)
dfs(0,9);
else {
ans++;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}
return;
}
//遍歷每列
for (int j = 0; j < n; j++) {
if (map[x][j] == 1 && judge(x, j ,queen)) {
map[x][j] = queen;
dfs(x + 1,queen);
map[x][j] = 1;
}
}
return;
}
public static boolean judge(int t, int i,int queen) //滿足題目要求的判斷函數
{
//當前位置上方是否進行了相同皇后的放置 這行以下的還沒放不檢查
for (int q = t - 1; q >= 0; q--)
if (map[q][i] == queen)
return false;
//檢查左對角線 這行以下的還沒放不檢查
for (int q = t - 1, w = i - 1; q >= 0 && w >= 0; q--, w--)
if (map[q][w] == queen)
return false;
//檢查右對角線 這行以下的還沒放不檢查
for (int q = t - 1, w = i + 1; q >= 0 && w <= n - 1; q--, w++)
if (map[q][w] == queen)
return false;
return true;
}
}
巧妙之處在於:
/*
如果在擺放好黑皇后的棋盤基礎之上,再開始擺放白皇后
*/
if (x == n) {
if(queen==6)
dfs(0,9);
總結:
(以前的博客有講到)
一、全排列
相當於往盒子裏面放東西,一維的操作,dfs在盒子中來回搜索
需要一個標記數組。
回溯:回退之後立馬回溯
出口:沒盒子走的時候,輸出序列然後返回接着
最終退回:是第一次dfs循環結束時,也就是全排列 (比如是3!)3開頭的搜索完之後,dfs終止。
二、走迷宮
走迷宮就開始接觸圖的遍歷了,此問題需要在每個點都進行上下左右四種重複嘗試,也需要一個標記數組來標記走過的點。
回溯:回退之後立馬回溯
出口:走出迷宮(到達目的點) 點判定
最終退回:搜索所有結果完之後
三、數獨
這種問題不是像走迷宮一樣 四個方向都需要嘗試
只需逐一遍歷一遍,每行填的結果都是一定的
回溯:可以讓1-9填數循環之後再開始回溯
出口:行數進行完之後
最終退回:一遍遍歷之後,直接退出
/*注意 System.exit(0)
是直接退回到調用dfs方法的位置,
也就是main方法*/
if(x==9){ //當x爲9時,也就是遍歷完整個數獨遊戲的時候
print();
System.exit(0); //直接返回第一步,這裏不回溯
}
四、2n_queen
這類問題 放置問題,和數獨一樣逐一遍歷,
回溯:回退過來立馬回溯
出口:行數進行完之後
最終退回:第一次遞歸的循環結束
由於此問題的特殊性,所以dfs每次直接進入下一行就可以了
黑白皇后問題:
/*如果在擺放好黑皇后的棋盤基礎之上,再開始擺放白皇后*/
if (x == n) {
if(queen==6)
dfs(0,9);