周末闲来无事,忽然想起大学时候学《数据结构》时候的期末上机考试,要求在两个小时内完成两道编程的题目。其中一道题目就是让编程解决“八皇后问题”。现在想起来还是挺有意思,就打算用 C# 再实现一次 :)
八皇后问题的大致意思是这样的:在一个 8*8 的矩形格子中排放 8 个皇后,要满足的条件包括:任意两个皇后都不能在同一行、同一列,也不能在同一条对角线(斜率等于1或-1)。
在考试的时候,我是用递归的方法解决的。现在想一想,还是用递归比较方便。但是需要注意的是,递归有个很大的毛病,就是递归的规模不太好控制,而且在递归很深的程序中,要调试也是一个很伤脑筋的问题。在有的公司,递归就是基本上禁止的。不过这里我就不去考虑非递归的解决方案了,反正是娱乐娱乐,何必自找麻烦呢:)
在使用递归解决此问题的时候,我采用的方法大致是这样:
- 将一个皇后向下移动一个位置;
- 如果没有成功移动(比如已经超出边界),失败;
- 如果成功移动,则判断当前位置是否可用(和其他的皇后时候冲突)?如果冲突,则重做 1;
- 继续给下一个皇后安排位置。
代码如下:
1
// AppEntry.cs
2
using System;
3
4
namespace 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
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1
// QueenRowCollection.cs
2
using System;
3
using System.Text;
4
5
namespace 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
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
1
// QueenRow.cs
2
using System;
3
using System.Text;
4
5
namespace 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
StringBuilder s = new StringBuilder();
43
44
foreach( bool b in columns ){
45
s.AppendFormat( "{0} ", (b ? "*" : "-") );
46
}
47
48
return s.ToString();
49
}
50
51
public int CurrentPosition
52
{
53
get { return currentPosition; }
54
}
55
56
private int currentPosition;
57
private int numberOfPositions;
58
private bool [] columns;
59
}
60
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
程序运行的时候,当皇后个数增加的时候,运行的时间也会急剧增加!下面这副图表示了皇后个数与运行时间的大致关系:
浙公网安备 33010602011771号