gpt4 book ai didi

algorithm - n皇后算法的所有可能解

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:40:03 24 4
gpt4 key购买 nike

当为 n-Queen 问题的所有可能解决方案实现算法时,我发现许多分支都达到了相同的解决方案。有没有什么好的方法可以生成 n-Queens 问题的每个唯一解决方案?如何避免不同分支(存储和比较除外)产生重复的解决方案?

这是我尝试过的第一个解决方案: http://www.ideone.com/hDpr3

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* crude */

#define QUEEN 'Q'
#define BLANK '.'

int is_valid (char **board, int n, int a, int b)
{
int i, j;

for (i=0; i<n; i++)
{
if (board[a][i] == QUEEN)
return 0;
if (board[i][b] == QUEEN)
return 0;
}

for (i=a, j=b; (i>=0) && (j>=0); i--, j--)
{
if (board[i][j] == QUEEN)
return 0;
}

for (i=a, j=b; (i<n) && (j<n); i++, j++)
{
if (board[i][j] == QUEEN)
return 0;
}

for (i=a, j=b; (i>=0) && (j<n); i--, j++)
{
if (board[i][j] == QUEEN)
return 0;
}

for (i=a, j=b; (i<n) && (j>=0); i++, j--)
{
if (board[i][j] == QUEEN)
return 0;
}
return 1;
}

void show_board (char **board, int n)
{
int i, j;

for (i=0; i<n; i++)
{
printf ("\n");
for (j=0; j<n; j++)
{
printf (" %c", board[i][j]);
}
}
}

int nqdfs_all (char **board, int n, int d)
{
int i, j, ret = 0;

/* the last queen was placed on the last depth
* therefore this dfs branch in the recursion
* tree is a solution, return 1
*/
if (d == n)
{
/* Print whenever we find one solution */
printf ("\n");
show_board (board, n);
return 1;
}

/* check all position */
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
{
if (is_valid (board, n, i, j))
{
board[i][j] = QUEEN;
nqdfs_all (board, n, d + 1);
board[i][j] = BLANK;
}
}
}

return ret;
}

int nqdfs_first (char **board, int n, int d)
{
int i, j, ret = 0;

/* the last queen was placed on the last depth
* therefore this dfs branch in the recursion
* tree is a solution, return 1
*/
if (d == n)
return 1;

/* check all position */
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
{
if (is_valid (board, n, i, j))
{
board[i][j] = QUEEN;
ret = nqdfs_first (board, n, d + 1);
if (ret)
{
/* if the first branch is found, tell about its
* success to its parent, we will not look in other
* solutions in this function.
*/
return ret;
}
else
{
/* this was not a successful path, so replace the
* queen with a blank, and prepare board for next
* pass
*/
board[i][j] = BLANK;
}
}
}
}

return ret;
}

int main (void)
{
char **board;
int n, i, j, ret;

printf ("\nEnter \"n\": ");
scanf ("%d", &n);

board = malloc (sizeof (char *) * n);
for (i=0; i<n; i++)
{
board[i] = malloc (sizeof (char) * n);
memset (board[i], BLANK, n * sizeof (char));
}

nqdfs_first (board, n, 0);
show_board (board, n);

printf ("\n");
return 0;
}

为了生成所有可能的解决方案,我使用了相同的代码 nqdfs_all () 函数,但没有将控制权返回给父级,而是继续枚举和检查。调用此函数会显示不同分支达到的重复结果。

最佳答案

您应该利用每个皇后必须放在不同列中的事实。如果您已经在前 k 列中放置了 k 个皇后,则递归地将编号为 k+1 的皇后放在第 k+1 列中,然后遍历第 1 行到第 n 行(而不是像您目前的算法那样遍历所有 n*n 单元格)。对每个有效位置继续使用 k:=k+1。这将避免任何重复的结果,因为该算法根本不会生成任何重复的电路板。

编辑:关于避免对称的问题:可以事先避免其中的一部分,例如,通过将第 1 列中的皇后 1 限制为第 1 行,...n/2。如果你想完全避免对称解决方案的输出,你必须将每个找到的解决方案存储在一个列表中,每当你找到一个新的解决方案,在打印出来之前,测试它的对称等价物之一是否已经存在于列表中。

为了提高效率,您可以使用每个板的“规范表示”,定义如下。生成一个给定的所有对称板,将每个对称板打包到一个字节数组中,并在这些数组中保留一个数组,该数组被解释为一个大数,具有最小值。这种打包表示是每 block 板的对称类的唯一标识符,可以很容易地放入字典/哈希表中,这使得测试该对称类是否已经出现非常有效。

关于algorithm - n皇后算法的所有可能解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7730360/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com