Jeff Somers's N Queens Solutions 最快的n皇后算法
/* Jeff Somers
*
* Copyright (c) 2002
*
* jsomers@alumni.williams.edu
* or
* allagash98@yahoo.com
*
* April, 2002
*
* Program: nq
*
* Program to find number of solutions to the N queens problem.
* This program assumes a twos complement architecture.
*
* For example, you can arrange 4 queens on 4 x 4 chess so that
* none of the queens can attack each other:
*
* Two solutions:
* _ Q _ _ _ _ Q _
* _ _ _ Q Q _ _ _
* Q _ _ _ _ _ _ Q
* _ _ Q _ and _ Q _ _
*
* Note that these are separate solutions, even though they
* are mirror images of each other.
*
* Likewise, a 8 x 8 chess board has 92 solutions to the 8 queens
* problem.
*
* Command Line Usage:
*
* nq N
*
* where N is the size of the N x N board. For example,
* nq 4 will find the 4 queen solution for the 4 x 4 chess
* board.
*
* By default, this program will only print the number of solutions,
* not board arrangements which are the solutions. To print the
* boards, uncomment the call to printtable in the Nqueen function.
* Note that printing the board arrangements slows down the program
* quite a bit, unless you pipe the output to a text file:
*
* nq 10 > output.txt
*
*
* The number of solutions for the N queens problems are known for
* boards up to 23 x 23. With this program, I've calculated the
* results for boards up to 21 x 21, and that took over a week on
* an 800 MHz PC. The algorithm is approximated O(n!) (i.e. slow),
* and calculating the results for a 22 x 22 board will take about 8.5
* times the amount of time for the 21 x 21 board, or over 8 1/2 weeks.
* Even with a 10 GHz machine, calculating the results for a 23 x 23
* board would take over a month. Of course, setting up a cluster of
* machines (or a distributed client) would do the work in less time.
*
* (from Sloane's On-Line Encyclopedia of Integer Sequences,
* Sequence A000170
* http://www.research.att.com/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi?Anum=000170
* )
*
* Board Size: Number of Solutions to Time to calculate
* (length of one N queens problem: on 800MHz PC
* side of N x N (Hours:Mins:Secs)
* chessboard)
*
* 1 1 n/a
* 2 0 < 0 seconds
* 3 0 < 0 seconds
* 4 2 < 0 seconds
* 5 10 < 0 seconds
* 6 4 < 0 seconds
* 7 40 < 0 seconds
* 8 92 < 0 seconds
* 9 352 < 0 seconds
* 10 724 < 0 seconds
* 11 2680 < 0 seconds
* 12 14200 < 0 seconds
* 13 73712 < 0 seconds
* 14 365596 00:00:01
* 15 2279184 00:00:04
* 16 14772512 00:00:23
* 17 95815104 00:02:38
* 18 666090624 00:19:26
* 19 4968057848 02:31:24
* 20 39029188884 20:35:06
* 21 314666222712 174:53:45
* 22 2691008701644 ?
* 23 24233937684440 ?
* 24 ? ?
*/ #include <stdio.h>
#include <stdlib.h>
#include <time.h> /*
Notes on MAX_BOARDSIZE: A 32 bit unsigned long is sufficient to hold the results for an 18 x 18
board (666090624 solutions) but not for a 19 x 19 board (4968057848 solutions). In Win32, I use a 64 bit variable to hold the results, and merely set the
MAX_BOARDSIZE to 21 because that's the largest board for which I've
calculated a result. Note: a 20x20 board will take over 20 hours to run on a Pentium III 800MHz,
while a 21x21 board will take over a week to run on the same PC. On Unix, you could probably change the type of g_numsolutions from unsigned long
to unsigned long long, or change the code to use two 32 bit ints to store the
results for board sizes 19 x 19 and up.
*/ #ifdef WIN32 #define MAX_BOARDSIZE 21
typedef unsigned __int64 SOLUTIONTYPE; #else #define MAX_BOARDSIZE 18
typedef unsigned long SOLUTIONTYPE; #endif #define MIN_BOARDSIZE 2 SOLUTIONTYPE g_numsolutions = ; /* Print a chess table with queens positioned for a solution */
/* This is not a critical path function & I didn't try to optimize it. */
void printtable(int boardsize, int* aQueenBitRes, SOLUTIONTYPE numSolution)
{
int i, j, k, row; /* We only calculated half the solutions, because we can derive
the other half by reflecting the solution across the "Y axis". */
for (k = ; k < ; ++k)
{
#ifdef WIN32
printf("*** Solution #: %I64d ***\n", * numSolution + k - );
#else
printf("*** Solution #: %d ***\n", * numSolution + k - );
#endif
for ( i = ; i < boardsize; i++)
{
unsigned int bitf;
/*
Get the column that was set (i.e. find the
first, least significant, bit set).
If aQueenBitRes[i] = 011010b, then
bitf = 000010b
*/
bitf = aQueenBitRes[i]; row = bitf ^ (bitf & (bitf - )); /* get least significant bit */
for ( j = ; j < boardsize; j++)
{
/* keep shifting row over to the right until we find the one '1' in
the binary representation. There will only be one '1'. */
if ( == k && ((row >> j) & ))
{
printf("Q ");
}
else if ( == k && (row & ( << (boardsize - j - )))) /* this is the board reflected across the "Y axis" */
{
printf("Q ");
}
else
{
printf(". ");
}
}
printf("\n");
}
printf("\n");
}
} /* The function which calculates the N queen solutions.
We calculate one-half the solutions, then flip the results over
the "Y axis" of the board. Every solution can be reflected that
way to generate another unique solution (assuming the board size
isn't 1 x 1). That's because a solution cannot be symmetrical
across the Y-axis (because you can't have two queens in the same
horizontal row). A solution also cannot consist of queens
down the middle column of a board with an odd number of columns,
since you can't have two queens in the same vertical row. This is a backtracking algorithm. We place a queen in the top
row, then note the column and diagonals it occupies. We then
place a queen in the next row down, taking care not to place it
in the same column or diagonal. We then update the occupied
columns & diagonals & move on to the next row. If no position
is open in the next row, we back track to the previous row & move
the queen over to the next available spot in its row & the process
starts over again.
*/
void Nqueen(int board_size)
{
int aQueenBitRes[MAX_BOARDSIZE]; /* results */
int aQueenBitCol[MAX_BOARDSIZE]; /* marks colummns which already have queens */
int aQueenBitPosDiag[MAX_BOARDSIZE]; /* marks "positive diagonals" which already have queens */
int aQueenBitNegDiag[MAX_BOARDSIZE]; /* marks "negative diagonals" which already have queens */
int aStack[MAX_BOARDSIZE + ]; /* we use a stack instead of recursion */
register int* pnStack; register int numrows = ; /* numrows redundant - could use stack */
register unsigned int lsb; /* least significant bit */
register unsigned int bitfield; /* bits which are set mark possible positions for a queen */
int i;
int odd = board_size & ; /* 0 if board_size even, 1 if odd */
int board_minus = board_size - ; /* board size - 1 */
int mask = ( << board_size) - ; /* if board size is N, mask consists of N 1's */ /* Initialize stack */
aStack[] = -; /* set sentinel -- signifies end of stack */ /* NOTE: (board_size & 1) is true iff board_size is odd */
/* We need to loop through 2x if board_size is odd */
for (i = ; i < ( + odd); ++i)
{
/* We don't have to optimize this part; it ain't the
critical loop */
bitfield = ;
if ( == i)
{
/* Handle half of the board, except the middle
column. So if the board is 5 x 5, the first
row will be: 00011, since we're not worrying
about placing a queen in the center column (yet).
*/
int half = board_size>>; /* divide by two */
/* fill in rightmost 1's in bitfield for half of board_size
If board_size is 7, half of that is 3 (we're discarding the remainder)
and bitfield will be set to 111 in binary. */
bitfield = ( << half) - ;
pnStack = aStack + ; /* stack pointer */ aQueenBitRes[] = ;
aQueenBitCol[] = aQueenBitPosDiag[] = aQueenBitNegDiag[] = ;
}
else
{
/* Handle the middle column (of a odd-sized board).
Set middle column bit to 1, then set
half of next row.
So we're processing first row (one element) & half of next.
So if the board is 5 x 5, the first row will be: 00100, and
the next row will be 00011.
*/
bitfield = << (board_size >> );
numrows = ; /* prob. already 0 */ /* The first row just has one queen (in the middle column).*/
aQueenBitRes[] = bitfield;
aQueenBitCol[] = aQueenBitPosDiag[] = aQueenBitNegDiag[] = ;
aQueenBitCol[] = bitfield; /* Now do the next row. Only set bits in half of it, because we'll
flip the results over the "Y-axis". */
aQueenBitNegDiag[] = (bitfield >> );
aQueenBitPosDiag[] = (bitfield << );
pnStack = aStack + ; /* stack pointer */
*pnStack++ = ; /* we're done w/ this row -- only 1 element & we've done it */
bitfield = (bitfield - ) >> ; /* bitfield -1 is all 1's to the left of the single 1 */
} /* this is the critical loop */
for (;;)
{
/* could use
lsb = bitfield ^ (bitfield & (bitfield -1));
to get first (least sig) "1" bit, but that's slower. */
lsb = -((signed)bitfield) & bitfield; /* this assumes a 2's complement architecture */
if ( == bitfield)
{
bitfield = *--pnStack; /* get prev. bitfield from stack */
if (pnStack == aStack) { /* if sentinel hit.... */
break ;
}
--numrows;
continue;
}
bitfield &= ~lsb; /* toggle off this bit so we don't try it again */ aQueenBitRes[numrows] = lsb; /* save the result */
if (numrows < board_minus) /* we still have more rows to process? */
{
int n = numrows++;
aQueenBitCol[numrows] = aQueenBitCol[n] | lsb;
aQueenBitNegDiag[numrows] = (aQueenBitNegDiag[n] | lsb) >> ;
aQueenBitPosDiag[numrows] = (aQueenBitPosDiag[n] | lsb) << ;
*pnStack++ = bitfield;
/* We can't consider positions for the queen which are in the same
column, same positive diagonal, or same negative diagonal as another
queen already on the board. */
bitfield = mask & ~(aQueenBitCol[numrows] | aQueenBitNegDiag[numrows] | aQueenBitPosDiag[numrows]);
continue;
}
else
{
/* We have no more rows to process; we found a solution. */
/* Comment out the call to printtable in order to print the solutions as board position*/
/* printtable(board_size, aQueenBitRes, g_numsolutions + 1); */
++g_numsolutions;
bitfield = *--pnStack;
--numrows;
continue;
}
}
} /* multiply solutions by two, to count mirror images */
g_numsolutions *= ;
} /* Print the results at the end of the run */
void printResults(time_t* pt1, time_t* pt2)
{
double secs;
int hours , mins, intsecs; printf("End: \t%s", ctime(pt2));
secs = difftime(*pt2, *pt1);
intsecs = (int)secs;
printf("Calculations took %d second%s.\n", intsecs, (intsecs == ? "" : "s")); /* Print hours, minutes, seconds */
hours = intsecs/;
intsecs -= hours * ;
mins = intsecs/;
intsecs -= mins * ;
if (hours > || mins > )
{
printf("Equals ");
if (hours > )
{
printf("%d hour%s, ", hours, (hours == ) ? "" : "s");
}
if (mins > )
{
printf("%d minute%s and ", mins, (mins == ) ? "" : "s");
}
printf("%d second%s.\n", intsecs, (intsecs == ? "" : "s")); }
} /* main routine for N Queens program.*/
int main(int argc, char** argv)
{
time_t t1, t2;
int boardsize; if (argc != ) {
printf("N Queens program by Jeff Somers.\n");
printf("\tallagash98@yahoo.com or jsomers@alumni.williams.edu\n");
printf("This program calculates the total number of solutions to the N Queens problem.\n");
printf("Usage: nq <width of board>\n"); /* user must pass in size of board */
return ;
} boardsize = atoi(argv[]); /* check size of board is within correct range */
if (MIN_BOARDSIZE > boardsize || MAX_BOARDSIZE < boardsize)
{
printf("Width of board must be between %d and %d, inclusive.\n",
MIN_BOARDSIZE, MAX_BOARDSIZE );
return ;
} time(&t1);
printf("N Queens program by Jeff Somers.\n");
printf("\tallagash98@yahoo.com or jsomers@alumni.williams.edu\n");
printf("Start: \t %s", ctime(&t1)); Nqueen(boardsize); /* find solutions */
time(&t2); printResults(&t1, &t2); if (g_numsolutions != )
{
#ifdef WIN32
printf("For board size %d, %I64d solution%s found.\n", boardsize, g_numsolutions, (g_numsolutions == ? "" : "s"));
#else
printf("For board size %d, %d solution%s found.\n", boardsize, g_numsolutions, (g_numsolutions == ? "" : "s"));
#endif
}
else
{
printf("No solutions found.\n");
} return ;
}
Jeff Somers's N Queens Solutions 最快的n皇后算法的更多相关文章
- 最快的Hash表算法
我们由一个简单的问题逐步入手:有一个庞大的字符串数组,然后给你一个单独的字符串,让你从这个数组中查找是否有这个字符串并找到它,你会怎么做?有一个方法最简单,老老实实从头查到尾,一个一个比较,直到找到为 ...
- 荷兰国旗问题、快排以及BFPRT算法
荷兰国旗问题 给定一个数组arr,和一个数num,请把小于num的数放数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边.要求额外空间复杂度O(1),时间复杂度O(N). 这个问题 ...
- 【算法】N Queens Problem
/* ** 目前最快的N皇后递归解决方法 ** N Queens Problem ** 试探-回溯算法,递归实现 */ #include "stdafx.h" #include & ...
- Jeff Dean 光辉事迹
这是Google 2007年的愚人节笑话,罗列了很多Jeff Dean的“光辉事迹”.大名鼎鼎的Jeff Dean想必不用我介绍了.……好吧,还是介绍一下,Jeff Dean是Google最早的一批员 ...
- 排序 之 快排、归并、插入 - <时间复杂度>----掌握思想和过程
俗话说:天下武功无坚不破,唯快不破.对于算法当然也是要使用时间最短.占用空间最小的算法来实现了. 注意:我代码里面打的备注仅供参考,建议不要背模板(因为没有固定的模板),可以写一个数列按着代码跑两圈或 ...
- 嫌弃Apriori算法太慢?使用FP-growth算法让你的数据挖掘快到飞起
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第20篇文章,我们来看看FP-growth算法. 这个算法挺冷门的,至少比Apriori算法冷门.很多数据挖掘的教材还会 ...
- 利用共享内存实现比NCCL更快的集合通信
作者:曹彬 | 旷视 MegEngine 架构师 简介 从 2080Ti 这一代显卡开始,所有的民用游戏卡都取消了 P2P copy,导致训练速度显著的变慢.针对这种情况下的单机多卡训练,MegEng ...
- 计算机网络传输层之TCP拥塞控制(慢开始与拥塞避免、快重传和快恢复)
文章转自:https://blog.csdn.net/weixin_43914604/article/details/105532044 学习课程:<2019王道考研计算机网络> 学习目的 ...
- 快Key:按一下鼠标【滚轮】,帮你自动填写用户名密码,快速登录,可制作U盘随身(开源免费-附安装文件和源代码)
* 代码以本文所附下载文件包为准,安装文件和源文件包均在本文尾部可下载. * 快Key及本文所有内容仅供交流使用,使用者责任自负,由快Key对使用者及其相关人员或组织造成的任何损失均由使用者自负,与本 ...
随机推荐
- PostgreSQL和Greenplum、Npgsql
PostgreSQL和Greenplum.Npgsql 想着要不要写,两个原因“懒”和“空”.其实懒和空也是有联系的,不是因为懒的写,而是因为对PostgreSQL和Npgsql的知识了解匮乏,也就懒 ...
- 扁平化设计的最新趋势 – 长阴影(Long Shadow)
随着互联网的发展,网页设计变得越来越复杂,如今设计的外观和感觉实现网站功能说使用的开发技术一样重要.互联网的功能远远不只是基本的信息共享,现在人们对网站的期望是远远大于几年前的. 如今,HTML5 & ...
- React中的PropTypes详解
propTypes用来规范props必须满足的类型,如果验证不通过将会有warn提示. React PropTypes的种类有: React.PropTypes.array // 队列 React.P ...
- @import和link的区别
@import和link的区别 1.link语法结构 <link href="CSSurl路径" rel="stylesheet" type=&qu ...
- MvvmLight框架使用入门(一)
MvvmLight是比较流行的MVVM框架,相对较为简单易用.可能正因为简单,对应的帮助文档不多,对初学者就不够友好了.这里会用几篇随笔,就个人对MvvmLight的使用经验,来做一个入门的介绍. 第 ...
- DIV+CSS常用网页布局技巧!
以下是我整理的DIV+CSS常用网页布局技巧,仅供学习与参考! 第一种布局:左边固定宽度,右边自适应宽度 HTML Markup <div id="left">Left ...
- JS魔法堂:追忆那些原始的选择器
一.前言 ...
- IOS开发中设置控件内容对齐方式时容易混淆的几个属性
IOS开发中四个容易混淆的属性: 1. textAligment : 文字的水平方向的对齐方式 1> 取值 NSTextAlignmentLeft = 0, // 左对齐 NST ...
- [Solution] Microsoft Windows 服务(1) C#创建Windows服务
Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序.这些服务可以在计算机启动时自动启动,可以暂停和重新启动而 ...
- WebApi中跨域解决办法
在做Web开发中,常常会遇到跨域的问题,到目前为止,已经有非常多的跨域解决方案.由于时间有限,本文不会深入. 笔者遇到的问题是Js调用WebAPI中的数据进行跨域的场景.涉及若干跨域方案: 方案1:j ...