[玩耍]八皇后问题动态演示

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

八皇后问题

简述: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(实现查找下一排列、重置排列等):

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:

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:

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:

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());
        }
    }
}

其他系统自动产生的文件代码不贴了。

posted @ 2017-05-06 17:33  蟹脑板  阅读(673)  评论(0编辑  收藏  举报