dfs2n皇后

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);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章