【算法】回溯法(N皇后问题) LeetCode51、52

前言

LeetCode51、52 属于经典的八皇后问题,前者是输入路径总数,后者是计算路径总数,可以说明白了51题,52题只需要在输出一个结果那里换成累加器就好了。此题主要是用了回溯法,其实就是深搜,如果一条路能走通就走到底,如果走到某一步走错了,回到上个岔路口换条路走就好了。

问题描述

先看51题

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

【算法】回溯法(N皇后问题) LeetCode51、52_第1张图片

给定一个整数 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;
  }

你可能感兴趣的:(算法,算法,leetcode,八皇后,回溯法)