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对使用者及其相关人员或组织造成的任何损失均由使用者自负,与本 ...
随机推荐
- ODBC连接问题
http://zhidao.baidu.com/link?url=EPEMTuGC1q5wWavZigWseoHOwRLvpHyAVsdIgMLspErJOUZMEepIICUnT9IdkPQlYTm ...
- selenium webdriver (python) 第一版PDF
前言 如果你是一位有python语言基础的同学,又想通过python+ selenium去实施自动化,那么你非常幸运的找到了这份文档,我也非常荣幸能为你的自动化学习之路带来一丝帮助. 其实,我在sel ...
- Android 学习笔记之AndBase框架学习(一) 实现多功能标题栏
PS:Volley框架终于通过看源码的方式完成了所有的学习..开始学习AndBase...AndBase的源码实在是多的离谱...因此就不对所有的源码进行分析了... 学习内容: 1.使用AndBas ...
- SQL Server技术问题之自定义函数优缺点
优点: 可以在SQL语句中调用,直接使用返回值,从而可以形成复杂的SQL应用. 缺点: 能在函数中使用的语句有严格限制: 不支持create.ALTER.drop等DDL(Data Definitio ...
- Main.storyboard中使用navigationController
传统使用navigationController的创建是在appdelegate中,使用storyboard的话必须在Main.storyboard文件中创建. 1.选中创建的navigationCo ...
- SQL Server存储过程复习(一)
--存储过程学习篇 --.简单存储过程不带参数的学习 IF OBJECT_ID('Orders_GetAllOrders','P') IS NOT NULL DROP PROCEDURE Orders ...
- 环信SDK与Apple Watch的结合(3)
第3章主要介绍怎样在Watch App的页面上显示iPhone程序里的数据.主要操作的是“EMWatchOCDemo WatchKit Extension”这个文件夹,附源码EMWatchOCDemo ...
- ubuntu E: Could not get lock /var/lib/dpkg/lock - open
sudo rm /var/lib/apt/lists/lock apt-get update
- 用UltraISO制作支持windows 7的U盘启动盘
用UltraISO制作U盘启动盘,有人写过,我也看过,不过依照网上的那些文章,成功的并不多,经过几次试验,在不同的主板环境下成功概率高的方法应该如下: 1. UltraISO建议9.3以上 2. ...
- 字符串与json之间的相互转化
先在数据库中建表: 再从后台将表取出来,然后转化为json格式,再将其执行ToString()操作后,赋值给前台的隐藏域. 注意引用using Newtonsoft.Json; 前台利用js将隐藏域中 ...