周末闲来无事,忽然想起大学时候学《数据结构》时候的期末上机考试,要求在两个小时内完成两道编程的题目。其中一道题目就是让编程解决“八皇后问题”。现在想起来还是挺有意思,就打算用 C# 再实现一次
八皇后问题的大致意思是这样的:在一个 8*8 的矩形格子中排放 8 个皇后,要满足的条件包括:任意两个皇后都不能在同一行、同一列,也不能在同一条对角线(斜率等于1或-1)。
在考试的时候,我是用递归的方法解决的。现在想一想,还是用递归比较方便。但是需要注意的是,递归有个很大的毛病,就是递归的规模不太好控制,而且在递归很深的程序中,要调试也是一个很伤脑筋的问题。在有的公司,递归就是基本上禁止的。不过这里我就不去考虑非递归的解决方案了,反正是娱乐娱乐,何必自找麻烦呢:)
在使用递归解决此问题的时候,我采用的方法大致是这样:
- 将一个皇后向下移动一个位置;
- 如果没有成功移动(比如已经超出边界),失败;
- 如果成功移动,则判断当前位置是否可用(和其他的皇后时候冲突)?如果冲突,则重做 1;
- 继续给下一个皇后安排位置。
结束条件就是如果第一个皇后的所有位置都尝试完毕仍然没有可用的解决方案或者最后一个皇后已经安排完毕。
代码如下:
1// AppEntry.cs
2using System;
3
4namespace Chenglin
5{
6 class AppEntry
7 {
8 static void Main(string[] args)
9 {
10 int queenNumber = 8;
11 QueenRowCollection q = new QueenRowCollection(queenNumber);
12
13 bool flag;
14 DateTime timeStarted = DateTime.Now;
15 flag = q.PositionQueens();
16 TimeSpan ts = DateTime.Now.Subtract( timeStarted );
17
18
19 if( flag ) {
20 Console.WriteLine( q.ToString() );
21 }
22 else {
23 Console.WriteLine( "Failed" );
24 }
25
26 Console.WriteLine( "{0} seconds has been elapsed.", ts.TotalSeconds );
27 }
28 }
29}
2using System;
3
4namespace Chenglin
5{
6 class AppEntry
7 {
8 static void Main(string[] args)
9 {
10 int queenNumber = 8;
11 QueenRowCollection q = new QueenRowCollection(queenNumber);
12
13 bool flag;
14 DateTime timeStarted = DateTime.Now;
15 flag = q.PositionQueens();
16 TimeSpan ts = DateTime.Now.Subtract( timeStarted );
17
18
19 if( flag ) {
20 Console.WriteLine( q.ToString() );
21 }
22 else {
23 Console.WriteLine( "Failed" );
24 }
25
26 Console.WriteLine( "{0} seconds has been elapsed.", ts.TotalSeconds );
27 }
28 }
29}
1// QueenRowCollection.cs
2using System;
3using System.Text;
4
5namespace Chenglin
6{
7 public class QueenRowCollection
8 {
9
10 public QueenRowCollection( int numberOfQueens ){
11 this.numberOfQueens = numberOfQueens;
12 this.rows = new QueenRow[ numberOfQueens ];
13
14 for( int i=0;i<numberOfQueens;i++ ){
15 rows[i] = new QueenRow( numberOfQueens );
16 }
17 }
18
19 public bool PositionQueens()
20 {
21 return PositionQueen( 0 );
22 }
23
24 private bool PositionQueen( int row )
25 {
26 if( row>=this.numberOfQueens ) {
27 return true;
28 }
29
30 QueenRow q = rows[row];
31 while( q.MoveNext() )
32 {
33 if( PositionAvailable( row, q.CurrentPosition ) ) {
34 // An available position has been found for the current queen,
35 // and try to find a proper position for the next queen.
36 //
37 // If no available position can be found for the next queen,
38 // the current queen should move to the next position and try again.
39 //
40 if( PositionQueen( row+1 ) )
41 {
42 // Both the current queen and the next queen
43 // have found available positions.
44 //
45 return true;
46 }
47 }
48 }
49
50 // No position is available for the current queen,
51 //
52 return false;
53 }
54
55 private bool PositionAvailable( int row, int column ){
56 for( int i=row-1; i>=0; i-- )
57 {
58 if( rows[i].PositionOccupied( column ) )
59 return false;
60
61 if( rows[i].PositionOccupied( column-(i-row) ) )
62 return false;
63
64 if( rows[i].PositionOccupied( column+(i-row) ) )
65 return false;
66 }
67
68 return true;
69 }
70
71 public override string ToString()
72 {
73 StringBuilder s = new StringBuilder();
74
75 foreach( QueenRow q in rows ){
76 s.AppendFormat( "{0}{1}", q, Environment.NewLine );
77 }
78
79 return s.ToString();
80 }
81
82 private int numberOfQueens;
83 private QueenRow [] rows;
84 }
85}
2using System;
3using System.Text;
4
5namespace Chenglin
6{
7 public class QueenRowCollection
8 {
9
10 public QueenRowCollection( int numberOfQueens ){
11 this.numberOfQueens = numberOfQueens;
12 this.rows = new QueenRow[ numberOfQueens ];
13
14 for( int i=0;i<numberOfQueens;i++ ){
15 rows[i] = new QueenRow( numberOfQueens );
16 }
17 }
18
19 public bool PositionQueens()
20 {
21 return PositionQueen( 0 );
22 }
23
24 private bool PositionQueen( int row )
25 {
26 if( row>=this.numberOfQueens ) {
27 return true;
28 }
29
30 QueenRow q = rows[row];
31 while( q.MoveNext() )
32 {
33 if( PositionAvailable( row, q.CurrentPosition ) ) {
34 // An available position has been found for the current queen,
35 // and try to find a proper position for the next queen.
36 //
37 // If no available position can be found for the next queen,
38 // the current queen should move to the next position and try again.
39 //
40 if( PositionQueen( row+1 ) )
41 {
42 // Both the current queen and the next queen
43 // have found available positions.
44 //
45 return true;
46 }
47 }
48 }
49
50 // No position is available for the current queen,
51 //
52 return false;
53 }
54
55 private bool PositionAvailable( int row, int column ){
56 for( int i=row-1; i>=0; i-- )
57 {
58 if( rows[i].PositionOccupied( column ) )
59 return false;
60
61 if( rows[i].PositionOccupied( column-(i-row) ) )
62 return false;
63
64 if( rows[i].PositionOccupied( column+(i-row) ) )
65 return false;
66 }
67
68 return true;
69 }
70
71 public override string ToString()
72 {
73 StringBuilder s = new StringBuilder();
74
75 foreach( QueenRow q in rows ){
76 s.AppendFormat( "{0}{1}", q, Environment.NewLine );
77 }
78
79 return s.ToString();
80 }
81
82 private int numberOfQueens;
83 private QueenRow [] rows;
84 }
85}
1// QueenRow.cs
2using System;
3using System.Text;
4
5namespace Chenglin
6{
7 public class QueenRow
8 {
9 public QueenRow( int numberOfPositions )
10 {
11 this.numberOfPositions = numberOfPositions;
12 this.currentPosition = -1;
13 this.columns = new bool[ numberOfPositions ];
14 }
15
16 public bool MoveNext(){
17 if( currentPosition>=0 && currentPosition<this.numberOfPositions ){
18 columns[currentPosition] = false;
19 }
20
21 if( currentPosition<this.numberOfPositions-1){
22 currentPosition ++;
23 columns[currentPosition] = true;
24 return true;
25 }
26 else {
27 currentPosition = -1;
28 return false;
29 }
30 }
31
32 public bool PositionOccupied( int column ){
33 if( column<0 || column>=numberOfPositions ){
34 return false;
35 }
36
37 return columns[column];
38 }
39
40 public override string ToString()
41 {
42
2using System;
3using System.Text;
4
5namespace Chenglin
6{
7 public class QueenRow
8 {
9 public QueenRow( int numberOfPositions )
10 {
11 this.numberOfPositions = numberOfPositions;
12 this.currentPosition = -1;
13 this.columns = new bool[ numberOfPositions ];
14 }
15
16 public bool MoveNext(){
17 if( currentPosition>=0 && currentPosition<this.numberOfPositions ){
18 columns[currentPosition] = false;
19 }
20
21 if( currentPosition<this.numberOfPositions-1){
22 currentPosition ++;
23 columns[currentPosition] = true;
24 return true;
25 }
26 else {
27 currentPosition = -1;
28 return false;
29 }
30 }
31
32 public bool PositionOccupied( int column ){
33 if( column<0 || column>=numberOfPositions ){
34 return false;
35 }
36
37 return columns[column];
38 }
39
40 public override string ToString()
41 {
42