【算法】回溯法(N皇后問題) LeetCode51、52

前言

LeetCode51、52 屬於經典的八皇后問題,前者是輸入路徑總數,後者是計算路徑總數,可以說明白了51題,52題只需要在輸出一個結果那裏換成累加器就好了。此題主要是用了回溯法,其實就是深搜,如果一條路能走通就走到底,如果走到某一步走錯了,回到上個岔路口換條路走就好了。

問題描述

先看51題

n 皇后問題研究的是如何將 n 個皇后放置在 n×n 的棋盤上,並且使皇后彼此之間不能相互攻擊。

在這裏插入圖片描述

給定一個整數 n,返回所有不同的 n 皇后問題的解決方案。

每一種解法包含一個明確的 n 皇后問題的棋子放置方案,該方案中 ‘Q’ 和 ‘.’ 分別代表了皇后和空位。

解題思路

利用回溯法,從第一行第一個位置開始放置第一個皇后,然後不斷向下一行每一個格嘗試放置皇后,如果可以放置就進行下一行直到第n行,如果不可以,回到上一行,把上一行的皇后嘗試換個位置,繼續。

代碼實現

  // 棋盤,放皇后
  public static int[][] arry;
  // 棋盤大小
  private static int size;
  // 結果
  private static List<List<String>> result = new ArrayList<>();
  // 棋盤大小
  public List<List<String>> solveNQueens(int n) {
    // 棋盤
    size = n;
    arry = new int[n][n];
    // 數據初始化,有A錯一次
    result = new ArrayList<>();
    // 邊界條件,A錯一次
    if (n == 1) {
      List<String> one = new ArrayList<>();
      one.add("Q");
      result.add(one);
      System.out.println(result);
      return result;
    }
    findQueen(0);
    System.out.println(result);
    return result;
  }
  // 尋找皇后節點
  public static void findQueen(int i) {
    // 八皇后的解
    if (i > size - 1) {
      List<String> list = new ArrayList<>();
      for (int x = 0; x < size; x++) {
        StringBuffer stringBuffer = new StringBuffer();
        for (int y = 0; y < size; y++) {
          if (arry[x][y] == 1) {
            stringBuffer.append("Q");
          } else {
            stringBuffer.append(".");
          }
        }
        list.add(stringBuffer.toString());
      }
      result.add(list);
      return;
    }
    // 深度回溯,遞歸算法
    for (int m = 0; m < size; m++) {
      // 檢查皇后擺放是否合適
      if (check(i, m)) {
        arry[i][m] = 1;
        findQueen(i + 1);
        // 清零,以免回溯的時候出現髒數據
        arry[i][m] = 0;
      }
    }
  }
  // 判斷節點是否合適
  public static boolean check(int k, int j) {
    // 檢查列衝突
    for (int i = 0; i < size; i++) {
      if (arry[i][j] == 1) {
        return false;
      }
    }
    // 檢查左對角線
    for (int i = k - 1, m = j - 1; i >= 0 && m >= 0; i--, m--) {
      if (arry[i][m] == 1) {
        return false;
      }
    }
    // 檢查右對角線
    for (int i = k - 1, m = j + 1; i >= 0 && m < size; i--, m++) {
      if (arry[i][m] == 1) {
        return false;
      }
    }
    return true;
  }

52解題思路

直接上代碼,只需要把51題輸入皇后位置圖樣的地方換上累加器即可。

  // 棋盤,放皇后
  public static int[][] arry;
  // 棋盤大小
  private static int size;
  // 結果
  private static int count = 0;
  // 棋盤大小
  public int totalNQueens(int n) {
    // 棋盤
    size = n;
    arry = new int[n][n];
    count = 0;
    // 邊界條件
    if (n == 1) {
      return 1;
    }
    findQueen(0);
    return count;
  }
  // 尋找皇后節點
  public static void findQueen(int i) {
    // 八皇后的解
    if (i > size - 1) {
      count++;
      return;
    }
    // 深度回溯,遞歸算法
    for (int m = 0; m < size; m++) {
      // 檢查皇后擺放是否合適
      if (check(i, m)) {
        arry[i][m] = 1;
        findQueen(i + 1);
        // 清零,以免回溯的時候出現髒數據
        arry[i][m] = 0;
      }
    }
  }
  // 判斷節點是否合適
  public static boolean check(int k, int j) {
    // 檢查列衝突
    for (int i = 0; i < size; i++) {
      if (arry[i][j] == 1) {
        return false;
      }
    }
    // 檢查左對角線
    for (int i = k - 1, m = j - 1; i >= 0 && m >= 0; i--, m--) {
      if (arry[i][m] == 1) {
        return false;
      }
    }
    // 檢查右對角線
    for (int i = k - 1, m = j + 1; i >= 0 && m < size; i--, m++) {
      if (arry[i][m] == 1) {
        return false;
      }
    }
    return true;
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章