0%

八皇后问题动态演示

学校组织的计算机技能大赛,题目解八皇后并做程序演示,顺便就贴博客上来。

八皇后问题

简述:8*8的棋盘,有八个皇后,每个皇后不能在同一行同一列同一斜线上,问有多少种可能的摆法。答案是92,这大家都知道。

#解法与优化 首先肯定是遍历嘛,关键是要剪枝。

##1.暴力枚举 8个子所有点遍历一遍,8个嵌套for,一共\(C_{64}^{8}\)种情况。曰曰

##2.回溯法 由于每个皇后不能在一行,那八个皇后就在八个不同行上面嘛,对于每个皇后/每一行,采用回溯法先第一行放一个,在第二行剩下7个位置中找第二个皇后可能的位置,以此类推,一共\(8^8 = 16777216\)种情况。

##3.全排列 由于每个皇后不同行不同列,那么在每个皇后占一行的基础上,每个皇后在0-7个列只能占一个,就相当于一个全排列,要考虑\(A_8^8 = 8! = 40320\)种情况,较上述两个方法已经快了很多了。网上也都是回溯和全排列的算法。但是事实上还能再剪枝。

##4.全排列再剪枝 对于全排列,依然可以剪枝。例如下图情况: 这里写图片描述 它的下一个排列是: 这里写图片描述 但是我们很明显的看到,第一、第二个皇后已经不满足条件了,后面的皇后无需再看了。因此我们直接跳到第1、2个皇后满足条件的排列: 这里写图片描述

最终,我们只需遍历3576种情况(根据实践得到的数据),这在全排列的基础上又优化了十倍多。这对八皇后适用,对n皇后都适用。

#程序实现 ##概况 使用C#编写,平台是win10,环境是.Net Framework 4.6.1。 这里写图片描述 下载地址:http://download.csdn.net/download/xienaoban/9835240

##特性 按“重置”即重置进度;

按“下一个”查找下一个符合条件的解并展示; 这里写图片描述

按“直接得出结果”不显示动画直接输出结果; 这里写图片描述

勾选“显示所有动画情况”演示所有遍历情况,勾选后再次点击“下一个”或“直接得出结果”演示所有遍历的情况;

遍历到当前方案时的遍历次数统计与可行方案统计显示在下方;

演示窗口自适应,修改窗口尺寸时始终保证棋盘最大化地显示在窗口中间;

演示画布采用双缓冲,防止演示动画时的窗口动画闪屏。

##代码 八皇后类EnumQueens.cs(实现查找下一排列、重置排列等):

1
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
86
87
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EightQueen
{
class EnumQueens
{
private int[] Board;

public EnumQueens()
{
Board = new int[8];
Reset();
}

public void Reset()
{
for (int i = 0; i < 8; ++i)
{
Board[i] = i;
}
}

public bool Next()
{
for (int i = Board.Length - 1; i > 0; --i)
{
if (Board[i] > Board[i - 1])
{
int val = Board[i - 1];
int j = Board.Length - 1;
for (; j >= i; --j)
{
if (Board[j] > val)
break;
}
SwapBoard(i - 1, j);
int l = i;
int r = Board.Length - 1;
while (l < r)
{
SwapBoard(l, r);
l++;
r--;
}
return true;
}
}
Reset();
return false;
}

public Point Check()
{
Point ans = new Point();
for (int i = 0; i < Board.Length; ++i)
{
for (int j = i + 1; j < Board.Length; ++j)
{
if (Math.Abs(i - j) == Math.Abs(Board[i] - Board[j]))
{
ans.X = i;ans.Y = j;
return ans;
}
}
}
ans.X = -1; ans.Y = -1;
return ans;
}

public int Get(int i)
{
return Board[i];
}

private void SwapBoard(int i, int j)
{
int t = Board[i];
Board[i] = Board[j];
Board[j] = t;
}
}
}

含棋盘的演示窗口:MainForm.cs:

1
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EightQueen
{
public partial class MainForm : Form
{
private int FrameLength = 30;
private int Fwidth, Fheight, Fleft, Fright, Ftop, Fbottom, Flength, Fdiameter;

private float Dif;

[DllImport("user32 ")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32 ")]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);


public MainForm()
{
InitializeComponent();
Dif = 0.8f;
Width = 400;
Height = 600;

PannelForm pForm = new PannelForm();
pForm.Show();
}

private void MainForm_SizeChanged(object sender, EventArgs e)
{
if (Program.Board.Get(0) == 0 && Program.Board.Get(1) == 1) PaintQueens(Color.Orange);
else PaintQueens(Color.LightGreen);
}

private void MainForm_Paint(object sender, PaintEventArgs e)
{
if (Program.Board.Get(0) == 0 && Program.Board.Get(1) == 1) PaintQueens(Color.Orange);
else PaintQueens(Color.LightGreen);
}

public void PaintQueens(Color c)
{
Bitmap bmp = new Bitmap(Width, Height);
Graphics grp = Graphics.FromImage(bmp);
grp.Clear(Color.Azure);
Pen pen;

CalFrame();

pen = new Pen(Brushes.DeepSkyBlue, Flength / 160);
for (int i = 1; i < 8; ++i)
{
grp.DrawLine(pen, new Point(Fleft + i * Fdiameter, Ftop), new Point(Fleft + i * Fdiameter, Fbottom));
grp.DrawLine(pen, new Point(Fleft, Ftop + i * Fdiameter), new Point(Fright, Ftop + i * Fdiameter));
}

pen = new Pen(Brushes.DodgerBlue, Flength / 100);
grp.DrawLine(pen, new Point(Fleft, Ftop), new Point(Fright, Ftop));
grp.DrawLine(pen, new Point(Fright, Ftop), new Point(Fright, Fbottom));
grp.DrawLine(pen, new Point(Fleft, Fbottom), new Point(Fright, Fbottom));
grp.DrawLine(pen, new Point(Fleft, Ftop), new Point(Fleft, Fbottom));

SolidBrush brush = new SolidBrush(c);
Rectangle rect;
int dif = (int)((1.0f - Dif) * Fdiameter/2);

for (int i = 0; i < 8; ++i)
{
rect = new Rectangle(Fleft + Program.Board.Get(i) * Fdiameter + dif, Ftop + i * Fdiameter + dif, Fdiameter - 2 * dif, Fdiameter - 2 * dif);
grp.FillEllipse(brush, rect);
}

this.CreateGraphics().DrawImage(bmp, 0, 0);
}

private void CalFrame()
{
int width = this.Width - 17;
int height = this.Height - 40;
Fwidth = width - FrameLength * 2;
Fheight = height - FrameLength * 2;
Flength = (Math.Min(Fwidth, Fheight) / 8) * 8;
Fleft = (width - Flength) / 2;
Fright = Fleft + Flength;
Ftop = (height - Flength) / 2;
Fbottom = Ftop + Flength;

Fdiameter = Flength / 8;
}
}
}

控制面板窗口PannelForm.cs:

1
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EightQueen
{
public partial class PannelForm : Form
{
private Button button1;
private Button button2;
private Label label1;
private Label label2;
private Label label3;
private Label label4;

public int Ergodic, Solution;
private Button button3;
private Button button4;
private Button button5;
private CheckBox checkBox1;

public PannelForm()
{
InitializeComponent();
}

private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.button3 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.checkBox1 = new System.Windows.Forms.CheckBox();
this.button5 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button1.Font = new System.Drawing.Font("微软雅黑", 15F);
this.button1.ForeColor = System.Drawing.SystemColors.HotTrack;
this.button1.Location = new System.Drawing.Point(12, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(268, 51);
this.button1.TabIndex = 0;
this.button1.Text = "重置";
this.button1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.button2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button2.Font = new System.Drawing.Font("微软雅黑", 15F);
this.button2.ForeColor = System.Drawing.SystemColors.HotTrack;
this.button2.Location = new System.Drawing.Point(12, 69);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(268, 51);
this.button2.TabIndex = 1;
this.button2.Text = "下一个";
this.button2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Font = new System.Drawing.Font("微软雅黑", 15F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.label1.ForeColor = System.Drawing.SystemColors.HotTrack;
this.label1.Location = new System.Drawing.Point(17, 231);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(132, 27);
this.label1.TabIndex = 2;
this.label1.Text = "遍历次数统计";
this.label1.Click += new System.EventHandler(this.label1_Click);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Font = new System.Drawing.Font("华文彩云", 60F);
this.label2.ForeColor = System.Drawing.SystemColors.HotTrack;
this.label2.Location = new System.Drawing.Point(23, 258);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(80, 83);
this.label2.TabIndex = 3;
this.label2.Text = "0";
this.label2.Click += new System.EventHandler(this.label2_Click);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Font = new System.Drawing.Font("微软雅黑", 15F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.label3.ForeColor = System.Drawing.SystemColors.HotTrack;
this.label3.Location = new System.Drawing.Point(17, 377);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(132, 27);
this.label3.TabIndex = 4;
this.label3.Text = "可行方案统计";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Font = new System.Drawing.Font("华文彩云", 71.99999F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.label4.ForeColor = System.Drawing.SystemColors.HotTrack;
this.label4.Location = new System.Drawing.Point(23, 404);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(97, 100);
this.label4.TabIndex = 5;
this.label4.Text = "0";
this.label4.Click += new System.EventHandler(this.label4_Click);
//
// button3
//
this.button3.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.button3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button3.Font = new System.Drawing.Font("微软雅黑", 15F);
this.button3.ForeColor = System.Drawing.SystemColors.HotTrack;
this.button3.Location = new System.Drawing.Point(12, 227);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(268, 140);
this.button3.TabIndex = 6;
this.button3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.button3.UseVisualStyleBackColor = true;
//
// button4
//
this.button4.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.button4.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button4.Font = new System.Drawing.Font("微软雅黑", 15F);
this.button4.ForeColor = System.Drawing.SystemColors.HotTrack;
this.button4.Location = new System.Drawing.Point(12, 373);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(268, 140);
this.button4.TabIndex = 7;
this.button4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.button4.UseVisualStyleBackColor = true;
//
// checkBox1
//
this.checkBox1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.checkBox1.ForeColor = System.Drawing.SystemColors.HotTrack;
this.checkBox1.Location = new System.Drawing.Point(17, 194);
this.checkBox1.Name = "checkBox1";
this.checkBox1.Size = new System.Drawing.Size(123, 21);
this.checkBox1.TabIndex = 0;
this.checkBox1.Text = "显示所有遍历情况";
this.checkBox1.UseVisualStyleBackColor = true;
this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged);
//
// button5
//
this.button5.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.button5.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button5.Font = new System.Drawing.Font("微软雅黑", 15F);
this.button5.ForeColor = System.Drawing.SystemColors.HotTrack;
this.button5.Location = new System.Drawing.Point(12, 126);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(268, 51);
this.button5.TabIndex = 8;
this.button5.Text = "直接得出结果";
this.button5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.button5.UseVisualStyleBackColor = true;
this.button5.Click += new System.EventHandler(this.button5_Click);
//
// PannelForm
//
this.BackColor = System.Drawing.Color.Azure;
this.ClientSize = new System.Drawing.Size(292, 535);
this.Controls.Add(this.button5);
this.Controls.Add(this.checkBox1);
this.Controls.Add(this.label4);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.button3);
this.Controls.Add(this.button4);
this.DoubleBuffered = true;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "PannelForm";
this.Text = "控制面板";
this.Load += new System.EventHandler(this.PannelForm_Load);
this.ResumeLayout(false);
this.PerformLayout();

}

private void button2_Click(object sender, EventArgs e)
{
if (!Next())
{
label4.Text = (Solution).ToString();
label2.Text = (Ergodic).ToString();
MessageBox.Show("所有情况已遍历!", "Duang!!!");
Reset();
}
else
{
label4.Text = (Solution).ToString();
label2.Text = (Ergodic).ToString();
Program.mForm.PaintQueens(Color.LightGreen);
}
}

private void button5_Click(object sender, EventArgs e)
{
while (Next())
{
if (checkBox1.Checked)
{
label4.Text = (Solution).ToString();
label2.Text = (Ergodic).ToString();
Program.mForm.PaintQueens(Color.LightGreen);
}
}
label4.Text = (Solution).ToString();
label2.Text = (Ergodic).ToString();
Program.mForm.PaintQueens(Color.LightGreen);
MessageBox.Show("所有情况已遍历!", "Duang!!!");
Reset();
}

private void button1_Click(object sender, EventArgs e)
{
Reset();
}

private void label1_Click(object sender, EventArgs e)
{

}

private void PannelForm_Load(object sender, EventArgs e)
{

}

public bool Next()
{
while (Program.Board.Next())
{
++Ergodic;
Point index = Program.Board.Check();
if (index.X != -1)
{
Point val = new Point();
val.X = Program.Board.Get(index.X);
val.Y = Program.Board.Get(index.Y);
bool flg = true;
while (flg = Program.Board.Next())
{
if (Program.Board.Get(index.X) != val.X|| Program.Board.Get(index.Y) != val.Y)
{
break;
}
}
if (!flg) break;
if(checkBox1.Checked) Program.mForm.PaintQueens(Color.Orange);
}
if (index.X != -1)
{
index = Program.Board.Check();
}
if (index.X == -1)
{
++Solution;
return true;
}
}
return false;
}

private void label4_Click(object sender, EventArgs e)
{

}

private void label2_Click(object sender, EventArgs e)
{

}

private void checkBox1_CheckedChanged(object sender, EventArgs e)
{

}

public void Reset()
{
label2.Text = (Ergodic = 0).ToString();
label4.Text = (Solution = 0).ToString();
Program.Board.Reset();
Program.mForm.PaintQueens(Color.Orange);
}
}
}

程序入口Program.cs:

1
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EightQueen
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>

static public EnumQueens Board;
static public MainForm mForm;

[STAThread]
static void Main()
{
Board = new EnumQueens();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(mForm = new MainForm());
}
}
}
其他系统自动产生的文件代码不贴了。