写这篇文章,是由于最近看到一篇帖子,要计算800个皇后。记得当初做八皇后问题的时候,要用一个二维矩阵来存棋盘状态,算法用的是比较直观的穷举,但是考虑要存一个800*800的棋盘状态,那么首先在资源上就处于劣势,因此在原先的算法进行修改,从而减少空间的使用。
简述一下八皇后问题,就是在8*8的棋盘上放置八个皇后,使得各个皇后之间不能相互吃掉,每个皇后可以吃掉横、竖、斜线这四条线内的任何子,这里的斜线是45度斜线,也就是说以皇后所在的点为中心画米字。N皇后的问题以此类推。
大致算法如下。
public class clsEightQueen
{
private int[] QueenVisited;
private int[] QueenIndex;
private bool bComputed;
public readonly uint QUEEN_NUM;
/// <summary>
/// Default constructor with 8-queen
/// </summary>
public clsEightQueen():this( 8 )
{
}
/// <summary>
/// Constructor with specific queen number
/// </summary>
/// <param name="QueenNum"></param>
public clsEightQueen( uint QueenNum )
{
QUEEN_NUM = QueenNum;
bComputed = false;
QueenVisited = new int[QUEEN_NUM];
QueenIndex = new int[QUEEN_NUM];
}
public int this[uint Index]
{
get
{
if( Index < QUEEN_NUM )
return QueenIndex[Index];
else
throw new Exception( "Invalid index!" );
}
}
private void InitArray()
{
// Init array
for( int i = 0; i < QUEEN_NUM; i++ )
{
QueenVisited[i] = 0;
QueenIndex[i] = -1;
}
}
/// <summary>
/// Compute the visited list under specific queen index
/// </summary>
/// <param name="CurQueenIndex"></param>
private void ComputeVisitedIndex( ref int CurQueenIndex )
{
// Reset visited list
for( int i = 0; i < QUEEN_NUM; i++ )
QueenVisited[i] = 0;
// Compute the visited list using previous queen value
for( int i = 0; i < CurQueenIndex; i++ )
{
QueenVisited[QueenIndex[i]]++;
if( QueenIndex[i] + CurQueenIndex - i < QUEEN_NUM )
QueenVisited[QueenIndex[i] + CurQueenIndex - i]++;
if( QueenIndex[i] - ( CurQueenIndex - i ) >= 0 )
QueenVisited[QueenIndex[i] - ( CurQueenIndex - i )]++;
}
}
/// <summary>
/// Set queen index
/// </summary>
/// <param name="CurQueenIndex"></param>
/// <returns></returns>
private bool SetQueenIndex( ref int CurQueenIndex )
{
int i = 0;
for( ; i < QUEEN_NUM; i++ )
if( QueenVisited[i] == 0 )
break;
if( i < QUEEN_NUM )
{
QueenIndex[ CurQueenIndex ] = i;
return true;
}
else
return false;
}
/// <summary>
/// Reset queen index
/// </summary>
/// <param name="CurQueenIndex"></param>
/// <returns></returns>
private bool SetNextQueenIndex( ref int CurQueenIndex )
{
// Roll back to previous data
int i = QueenIndex[CurQueenIndex];
i++;//Goto next index
for( ; i < QUEEN_NUM; i++ )
if( QueenVisited[i] == 0 )
break;
if( i < QUEEN_NUM )
{
QueenIndex[ CurQueenIndex ] = i;
CurQueenIndex++;
return true;
}
else
return false;
}
/// <summary>
/// Compute the queen index list
/// </summary>
/// <returns></returns>
public bool Compute()
{
int nCurQueenIndex = 0;
bComputed = false;
InitArray();
while( nCurQueenIndex < QUEEN_NUM && nCurQueenIndex >= 0 )
{
ComputeVisitedIndex( ref nCurQueenIndex );
if( SetQueenIndex( ref nCurQueenIndex ) )
nCurQueenIndex++;
else
{
//Roll back
do
{
nCurQueenIndex--;
ComputeVisitedIndex( ref nCurQueenIndex );
}while( !SetNextQueenIndex( ref nCurQueenIndex ) && nCurQueenIndex >= 0 );
}
}
bComputed = ( nCurQueenIndex == QUEEN_NUM );
return bComputed;
}
}
调用代码如下:
clsEightQueen myEightQueen = new clsEightQueen();
if( myEightQueen.Compute() )
{
for( uint i = 0; i < myEightQueen.QUEEN_NUM; i++ )
Debug.WriteLine( string.Format( "{0}:{1}", i, myEightQueen[i] ) );
}
以上代码在算40个皇后以上问题的时候,速度就很慢了。因此有些地方还是需要再考虑一下,看看是否有更好的算法。除此外,以上是使用单线程来解的,那么如何用多线程来解也是值得琢磨的。