65,182
社区成员




八皇后问题 如何使用一句c++代码解决呢?
我看过类似的,别的语言写的一句搞定。但是,一句c++代码解决该问题的却没有哎,
有没有人知道?
Veni, vidi, vici~~~
#include <cstdio>
#include <algorithm>
// print pattern
void pp(int *p)
{
for (int i = 0, j; i < 8; i++, puts(""))
for (j = 0; j < 8; j++) printf("%c", p[i] == j ? 'Q' : '.');
puts("");
}
// check pattern
#define cp(a, b) (1 << p[a]) & (1 << (p[b] + a - b)) || \
(1 << p[a]) & (1 << (p[b] - a + b))
// solve EightQueens problem with one statement
int main()
{
int p[] = {0, 1, 2, 3, 4, 5, 6, 7}, n = 0;
while (std::next_permutation(p, p + 8))
if (!(cp(0, 1) || cp(0, 2) || cp(0, 3) || cp(0, 4) || cp(0, 5) ||
cp(0, 6) || cp(0, 7) || cp(1, 2) || cp(1, 3) || cp(1, 4) ||
cp(1, 5) || cp(1, 6) || cp(1, 7) || cp(2, 3) || cp(2, 4) ||
cp(2, 5) || cp(2, 6) || cp(2, 7) || cp(3, 4) || cp(3, 5) ||
cp(3, 6) || cp(3, 7) || cp(4, 5) || cp(4, 6) || cp(4, 7) ||
cp(5, 6) || cp(5, 7) || cp(6, 7))) n++, pp(p);
printf("There are total %d patterns\n", n);
return 0;
}
先在对角线上放上8个Q(这个排列当然是不符合要求的),然后检查其余8! - 1 = 40319种排列是否符合要求就可以了,因为每行只有一个Q,符合条件的必然是8行的某种排列。
你整个2^64次测试,不是超算就根本不可能有效时间之内算出来嘛~~~
要求一行求出来,你写5行算什么事~
思路:a[8][8]数组,每个数组元素非0即1。8皇后要求每行只有一个元素为1(即全部行元素相加结果为1);若第1行异或第2行对应列元素,结果再异或第3行对应列元素,依次类推,如果最终异或结果的毎列全为1,即所有行的异或结果为0xFF,此时若任意45度或135度斜线上无皇后冲突,则为一个合法的8皇后布局。
方案:将a[8][8]数组用unsigned long long x即8*8=64位变量x存储,其中每个字节代表1行,不用相加即可简单判断每行只有一个元素为1(值为1,2,4,8,16,32,64,128中任意一个),这仅需一条语句即可;至于所有行对应列的异或运算也只需1条语句。任意45度或135度斜线不能有皇后冲突,可使用左移位或右移位实现。
编程:变量 x从0至2^64 -1=0xFFFFFFFFFFFFF循环一遍,即可求得所有可行解。若考虑8皇后问题的4个方向的对称性,则x从0至2^62 -1=0x3FFFFFFFFFFFFFFF循环一遍即可。如何取出8个字节其实很简单:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main() {
for (unsigned long long x=0; x <= 0xFFFFFFFFFFFFFFFF; x++) {
unsigned char k, h, m, s, b[10], t[100], (&a)[8]=(unsigned char(&)[8])x; //a[k]代表8个字节
for (k=s=0; k < 8; s ^= a[k], k++){
if(!(a[k]==1||a[k]==2||a[k]==4||a[k]==8||a[k]==16||a[k]==32||a[k]==64||a[k]==128)) goto notq;
sprintf((char*)t + k * sizeof "1234567\n", "%8s\n", _itoa(a[k], (char*)b, 2));
}
for (k = 0; k < 7; k++)
for (h = k + 1; m = (h - k + 8) % 8, h < 8; h++)
if (a[k] == (a[h] << m) || a[k] == (a[h] >> m)) goto notq;
if (s == 0xFF) printf("%s\n\n", t); else notq:;
}
}
主函数内正好10行之内完成求解8皇后问题,简单验证x = 0x1040022004010880是一个解。当然,如果对求解过程进行一点优化,例如最后一个皇后位置直接确定(判定到a[7]即可,a[8]自动确定),代码就要变长但循环次数降为再除以8。更多有趣面试难点问题参见https://www.zhihu.com/question/825891126/answer/4843052142?utm_psn=1837747917399674880
只输出一种解可以:)
#include <stdio.h>
#include <string.h>
int main()
{
char q[64];
memset(q, '.', 64);
for (int i = 0, x = 0x2be6388; i < 8; i++, x /= 10) q[i * 8 + x % 10] = 'Q';
for (int i = 0; i < 8; i++) printf("%.8s\n", &q[i * 8]);
return 0;
}