51. N-Queens (H)

N-Queens (H)

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
在这里插入图片描述
Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens’ placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

Example:

Input: 4
Output: [
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.

题意

在 n * n 的棋盘上放置n个皇后,使得每一行、每一列、每一条对角线有且只有一个皇后。记录每一种放置方法。

思路

问题实质上可以抽象为对 1 ~ n 这n个自然数进行全排列,排列中数字i所处的位置下标代表行号,i代表列号,那么得到的排列组合必定满足每行每列不重复,只要再对对角线位置进行判断即可。使用回溯法。


代码实现

class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> ans = new ArrayList<>();
        generate(new int[n], new boolean[n], 0, ans);
        return ans;
    }

    // queen记录已经放置的皇后的行列坐标,occupied记录指定列是否已经放置皇后
    private void generate(int[] queen, boolean[] occupied, int row, List<List<String>> ans) {
        // 所有行放置完毕,保存当前放置方法
        if (row == queen.length) {
            List<String> list = new ArrayList<>();
            for (int i = 0; i < queen.length; i++) {
                StringBuilder line = new StringBuilder();
                for (int j = 0; j < queen.length; j++) {
                    line.append(j == queen[i] ? 'Q' : '.');
                }
                list.add(line.toString());
            }
            ans.add(list);
            return;
        }

        // 遍历当前行的所有列,寻找可放置的位置
        for (int col = 0; col < queen.length; col++) {
            // 当前列还未放置皇后
            if (!occupied[col]) {
                // 判断位置(row, col)在对角线方向上是否已放置皇后
                boolean isValid = true;
                for (int preRow = 0; preRow < row; preRow++) {
                    if (Math.abs(preRow - row) == Math.abs(queen[preRow] - col)) {
                        isValid = false;
                        break;
                    }
                }
				
                // 位置有效,则向下一行递归
                if (isValid) {
                    occupied[col] = true;
                    queen[row] = col;
                    generate(queen, occupied, row + 1, ans);
                    occupied[col] = false;
                }
            }
        }
    }
}
以下使用爬山法求解n皇后问题的代码存在bug,请找出 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <vector> #include <algorithm> #include <random> using namespace std; // 显示棋盘 void print_board(int *queens, int n) { printf("\n解决方案:\n"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (queens[i] == j) { printf("Q "); } else { printf(". "); } } printf("\n"); } } int *diag1_conflicts; int *diag2_conflicts; int pos_diag1(int row, int col) { return row + col; } int pos_diag2(int row, int col, int n) { return row - col + n - 1; } bool hill_climbing_n_queens(int n, int max_iterations) { int *queens = (int *)malloc(n * sizeof(int)); diag1_conflicts = (int *)calloc(2 * n, sizeof(int)); diag2_conflicts = (int *)calloc(2 * n, sizeof(int)); // int *col_conflicts = (int *)calloc(n, sizeof(int)); if (queens == NULL || /*col_conflicts == NULL || */ diag1_conflicts == NULL || diag2_conflicts == NULL) { printf("内存分配失败\n"); return false; } // 随机初始化并计算初始冲突 vector<int> queens_position; for (int i = 0; i < n; i++) { queens_position.push_back(i); } std::mt19937 gen(std::random_device{}()); shuffle(queens_position.begin(), queens_position.end(), gen); for (int i = 0; i < n; i++) { queens[i] = queens_position[i]; // col_conflicts[queens[i]]++; diag1_conflicts[i + queens[i]]++; diag2_conflicts[i - queens[i] + n - 1]++; } printf("使用优化爬山法求解 %d 皇后问题\n", n); for (int iter = 0; iter < max_iterations; iter++) { // 检查是否找到解 bool found_solution = true; for (int i = 0; i < n; i++) { if (/*col_conflicts[queens[i]] > 1 || */ diag1_conflicts[i + queens[i]] > 1 || diag2_conflicts[i - queens[i] + n - 1] > 1) { found_solution = false; break; } } if (found_solution) { printf("\n在第 %d 次迭代中找到解决方案!\n", iter); print_board(queens, n); free(queens); // free(col_conflicts); free(diag1_conflicts); free(diag2_conflicts); return true; } int row1_to_change = -1; int row2_to_change = -1; // 对每对相邻行的皇后,尝试互相交换 for (int row1 = 0; row1 < n; row1++) { int col1 = queens[row1]; bool isFound = false; for (int row2 = 0; row2 < n; row2++) { if (row1 == row2) { continue; } int col2 = queens[row2]; // 计算当前冲突数 int current_conflicts = diag1_conflicts[pos_diag1(row1, col1)] - 1 + diag2_conflicts[pos_diag2(row1, col1, n)] - 1 + diag1_conflicts[pos_diag1(row2, col2)] - 1 + diag2_conflicts[pos_diag2(row2, col2, n)] - 1; int new_conflicts = diag1_conflicts[pos_diag1(row2, col1)] - 1 + diag2_conflicts[pos_diag2(row2, col1, n)] - 1 + diag1_conflicts[pos_diag1(row1, col2)] - 1 + diag2_conflicts[pos_diag2(row1, col2, n)] - 1; if(new_conflicts < current_conflicts){ isFound = true; row1_to_change = row1; row2_to_change = row2; break; } } if(isFound){ break; } } // for (int row = 0; row < n - 1; row++) //{ /*int row1 = row; int row2 = row + 1; int col1 = queens[row]; int col2 = queens[row2];*/ // 计算当前冲突数 /*int current_conflicts = diag1_conflicts[pos_diag1(row1, col1)] - 1 + diag2_conflicts[pos_diag2(row1, col1, n)] - 1 + diag1_conflicts[pos_diag1(row2, col2)] - 1 + diag2_conflicts[pos_diag2(row2, col2, n)];*/ /*int current_conflicts = (diag1_conflicts[row1 + col1] - 1) + (diag2_conflicts[row1 - row + n - 1] - 1) + (diag1_conflicts[row1 + 1 +])*/ /*int current_conflicts = (diag1_conflicts[row1 + col1] - 1) + (diag2_conflicts[row2 - col2 + n - 1]) + (diag1_conflicts[row1 + col1 + 1] - 1) + (diag2_conflicts[row2 - col2 + n - 2]);*/ /*// 计算修改后的冲突数 int new_conflicts = diag1_conflicts[pos_diag1(row1 + 1, col1)] - 1 + diag2_conflicts[pos_diag2(row1 + 1, col1, n)] - 1 + diag1_conflicts[pos_diag1(row2 - 1, col2)] - 1 + diag2_conflicts[pos_diag2(row2 - 1, col2, n)]; // 计算是否保留该答案 int improvement = current_conflicts - new_conflicts; if (improvement > best_improvement) { best_improvement = improvement; best_row = row; }*/ //} /*for (int row = 0; row < n; row++) { int current_col = queens[row]; // 计算当前位置的冲突数 int current_conflicts = (col_conflicts[current_col] - 1) + (diag1_conflicts[row + current_col] - 1) + (diag2_conflicts[row - current_col + n - 1] - 1); for (int new_col = 0; new_col < n; new_col++) { if (new_col == current_col) continue; // 计算新位置的冲突数 int new_conflicts = col_conflicts[new_col] + diag1_conflicts[row + new_col] + diag2_conflicts[row - new_col + n - 1]; int improvement = current_conflicts - new_conflicts; if (improvement > best_improvement) { best_improvement = improvement; best_row = row; best_col = new_col; } } }*/ if (row1_to_change == -1) { // 随机重启 /*for (int i = 0; i < n; i++) { //col_conflicts[queens[i]]--; diag1_conflicts[i + queens[i]]--; diag2_conflicts[i - queens[i] + n - 1]--; queens[i] = rand() % n; //col_conflicts[queens[i]]++; diag1_conflicts[i + queens[i]]++; diag2_conflicts[i - queens[i] + n - 1]++; }*/ vector<int> queens_position; for (int i = 0; i < n; i++) { queens_position.push_back(i); } std::mt19937 gen(std::random_device{}()); shuffle(queens_position.begin(), queens_position.end(), gen); for (int i = 0; i < n; i++) { queens[i] = queens_position[i]; // col_conflicts[queens[i]]++; diag1_conflicts[i + queens[i]]++; diag2_conflicts[i - queens[i] + n - 1]++; } printf("迭代 %d: 随机重启\n", iter + 1); } else { // todo // 更新冲突数组并移动皇后 diag1_conflicts[pos_diag1(row1_to_change, queens[row1_to_change])]--; diag2_conflicts[pos_diag2(row1_to_change, queens[row1_to_change], n)]--; diag1_conflicts[pos_diag1(row2_to_change, queens[row2_to_change])]--; diag2_conflicts[pos_diag2(row2_to_change, queens[row2_to_change], n)]--; swap(queens[row1_to_change], queens[row2_to_change]); diag1_conflicts[pos_diag1(row1_to_change, queens[row1_to_change])]++; diag2_conflicts[pos_diag2(row1_to_change, queens[row1_to_change], n)]++; diag1_conflicts[pos_diag1(row2_to_change, queens[row2_to_change])]++; diag2_conflicts[pos_diag2(row2_to_change, queens[row2_to_change], n)]++; /*diag1_conflicts[pos_diag1(best_row, queens[best_row])]--; diag2_conflicts[pos_diag2(best_row, queens[best_row], n)]--; diag1_conflicts[pos_diag1(best_row + 1, queens[best_row + 1])]--; diag2_conflicts[pos_diag2(best_row + 1, queens[best_row + 1], n)]--; swap(queens[best_row], queens[best_row + 1]); diag1_conflicts[pos_diag1(best_row, queens[best_row])]++; diag2_conflicts[pos_diag2(best_row, queens[best_row], n)]++; diag1_conflicts[pos_diag1(best_row + 1, queens[best_row + 1])]++; diag2_conflicts[pos_diag2(best_row + 1, queens[best_row + 1], n)]++;*/ /*int old_col = queens[best_row]; //col_conflicts[old_col]--; diag1_conflicts[best_row + old_col]--; diag2_conflicts[best_row - old_col + n - 1]--; queens[best_row] = best_col;*/ // col_conflicts[best_col]++; // diag1_conflicts[best_row + best_col]++; // diag2_conflicts[best_row - best_col + n - 1]++; printf("迭代 %d: %d 与 %d行交换", iter + 1, row1_to_change, row2_to_change); } } printf("在 %d 次迭代内未找到解决方案\n", max_iterations); free(queens); // free(col_conflicts); free(diag1_conflicts); free(diag2_conflicts); return false; } int main() { int n; int max_iterations; printf("请输入皇后数量 n: "); scanf("%d", &n); printf("请输入最大迭代次数: "); scanf("%d", &max_iterations); bool result2 = hill_climbing_n_queens(n, max_iterations); return 0; }
10-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值