我应该在1秒内解决16-Queens Problem。 我使用了如下的回溯算法。 当N小于13时,此代码足以在1秒内解决N-Queens问题。 但是如果N大于13则需要很长时间。
我该如何改进?
#include <stdio.h>
#include <stdlib.h>
int n;
int arr[100]={0,};
int solution_count = 0;
int check(int i)
{
int k=1, ret=1;
while (k < i && ret == 1) {
if (arr[i] == arr[k] ||
abs(arr[i]-arr[k]) == abs(i-k))
ret = 0;
k++;
}
return ret;
}
void backtrack(int i)
{
if(check(i)) {
if(i == n) {
solution_count++;
} else {
for(int j=1; j<=n; j++) {
arr[i+1] = j;
backtrack(i+1);
}
}
}
}
int main()
{
scanf("%d", &n);
backtrack(0);
printf("%d", solution_count);
}
答案 0 :(得分:4)
你的算法几乎没问题。一个小的改变可能会给你足够的时间来提高解决方案的速度。此外,还有一个数据结构更改,可以让您进一步缩短时间。
首先,稍微调整算法:而不是一直等待检查,直到你放置所有N
个皇后,提前检查:每次你要放置一个新女王时,检查另一个女王是否是在进行arr[i+1] = j;
分配之前占据相同的列或相同的对角线。这将为您节省大量的CPU周期。
现在你需要加快检查下一个女王。为此,您必须更改数据结构,以便可以在没有任何循环的情况下执行所有检查。以下是如何做到这一点:
N
行N
列2N-1
上升对角线2N-1
下降对角线由于没有两个皇后可以在四个&#34;尺寸中的任何一个中占据相同的位置。上面,你需要一个最后三件事的布尔值数组;保证行不同,因为代表行的i
backtrack
参数保证不同。
N
最多为16,2N-1
最多为31,因此您可以将uint32_t
用于您的位阵列。现在,您可以通过按位和c
应用列位掩码和&
来检查是否采用了列1 << c
。对角位掩码也是如此。
注意:在一秒钟内完成16皇后问题会相当棘手。 very highly optimized program在800 MHz PC上在23秒内完成。 3.2 GHz应该可以提供大约4倍的加速,但是获得解决方案大约需要8秒。
答案 1 :(得分:1)
我会将while (k < i && ret == 1) {
更改为while (k < i) {
而不是ret = 0;
做return 0;
。
(这将在每次迭代时保存一个检查。可能是你的编译器仍然执行此操作,或者其他一些性能技巧,但这可能会有所帮助。)