1、福 建 工 程 学 院课 程 设 计课程:VC+面向对象程序设计题目: 皇后问题 专业: 电子科学与技术 班级: 0902 座号: 20 姓名: 陈华鑫 2012 年 3 月 15 日一、实践目的与要求: 要求在一个 nn 的棋盘上放置 n 个皇后,要求放置的 n 个皇后不会互相吃掉对方;皇后棋子可以吃掉任何它所在的那一行、那一列,以及那两条对角线上的任何棋子。 熟悉 visual C+编程环境二、实践工具与准备在开始实验前,应回顾或复习相关内容。需要一台计算机,其中安装有 Visual C+ 6 .0 集成开发环境软件。课题分析三、课题分析八皇后问题是一个古老而著名的问题,它是回溯算法的典型
2、例题。该问题是十九世纪德国著名数学家高斯于 1850 年提出的:在 8行 8 列的国际象棋棋盘上摆放着八个皇后。使他们之间不能互相攻击。若两个皇后位于同一行、同一列或同一对角线上,则它们之间就可以互相攻击。后来人们从 8 皇后问题延伸到了 n 皇后问题,问题的重点即使每两个皇后都不能在同一行、同一列、同一对角线上。在分析这个问题时,我们不妨从第一列开始放置皇后。这里我们选择使用回溯法即经典的递归法来求解 n 皇后问题,这个算法将在棋盘上一列一列地放置皇后直到 n 个皇后在不相互攻击的情况下都被摆放在棋盘上,算法便终止。当一个新加入的皇后因为与已经存在的皇后之间相互攻击而不能被摆在棋盘上时,算法
3、便发生回溯。一旦发生这种情况,就试图把最后放在棋盘上的皇后移动到其他地方。这样做是为了让新加入的皇后能够在不与其它皇后相互攻击的情况下被摆放在棋盘的适当位置上。如图所示是两种满足要求摆放皇后的图。四、设计流程 打开 visual C+新建一个 MFC APPwizrd(exe) 工程,由于该 n 皇后问题是由 8 皇后问题衍变而来的,我们为了纪念高斯这位伟大的数学家,我们把工程命名为 EightQueen。 按如图为窗体放置相应的组件,将窗体的名称改成“皇后问题”并按以下表格设置好相关的 ID 和属性标题 ID 属性分组框开始 IDC_START暂停/单步 IDC_PAUSEn 值 IDC_B
4、OARD_SIZE单步 IDC_STEP_BY不中断 IDC_NO_INT继续 IDC_CONTINUE停止 IDC_STOPQueen_panel IDC_QUEEN_PANEL关于 IDC_ABOUT按 Ctrl+W 为 IDC_QUEEN_PANEL 添加一个 Type 为 QueenPanel 的成员变量 m_panel 为组件画板新建一个名为 QueenPanel 的类,并添加以下成员:public privateQueenPanel(); void DrawBoard(CDC *pDC, int size, int cell);QueenPanel(int size); int *
5、queen;virtual QueenPanel(); int n;void SetSize(int size); HANDLE queen_mutex;void SetQueen(int *newq);void SetQueen(int row, int col) 为 CEightQueenDlg 类添加以下变量及函数pubilc privatevoid UpdateUI(); static DWORD WINAPI ThreadGo( LPVOID lpParam ) ;void WINAPI Go(); void UpdateQPanel(int *queen);virtual void
6、 OnOK(); void UpdateQPanel(int row, int col);virtual void OnCancel(); void DoPause();void WINAPI Step(int i);BOOLEAN m_step, m_no_int;int count;int n;int *queen;BOOLEAN *rk;BOOLEAN *lk;BOOLEAN *mk;BOOLEAN step, no_int;HANDLE pause_event, this_mutex;BOOLEAN canceling, running, pausing;五、程序代码: 为单步单选框控
7、件添加 BN_CLICKED 消息映射,代码如下:CButton *step = (CButton *)GetDlgItem(IDC_STEP_BY);m_step = (step-GetCheck()=BST_CHECKED)?TRUE:FALSE;if(m_step) CButton *autoBtn = (CButton *)GetDlgItem(IDC_NO_INT);autoBtn-SetCheck(FALSE);m_no_int = FALSE; 为不中断单选框控件添加 BN_CLICKED 消息映射,代码如下:CButton *autoBtn = (CButton *)GetDl
8、gItem(IDC_NO_INT);m_no_int = (autoBtn-GetCheck()=BST_CHECKED)?TRUE:FALSE;if(m_no_int) CButton *step = (CButton *)GetDlgItem(IDC_STEP_BY);step-SetCheck(FALSE);m_step = FALSE; 为开始按钮控件添加 BN_CLICKED 消息映射,代码如下:DWORD dwThreadId; HANDLE hThread; CString str;GetDlgItem(IDC_BOARD_SIZE)-GetWindowText(str);int
9、 newn = atoi(str);if(newnGo();return 0; 为暂停/单步按钮控件添加 BN_CLICKED 消息映射,代码如下:WaitForSingleObject(this_mutex,INFINITE);step = TRUE;if(pausing) SetEvent(pause_event); ReleaseMutex(this_mutex); UpdateUI(); 为继续按钮控件添加 BN_CLICKED 消息映射,代码如下WaitForSingleObject(this_mutex,INFINITE);step = FALSE;if(pausing) SetE
10、vent(pause_event); ReleaseMutex(this_mutex);UpdateUI(); 为停止按钮控件添加 BN_CLICKED 消息映射,代码如下WaitForSingleObject(this_mutex, INFINITE);step = FALSE;canceling = TRUE;if(pausing) SetEvent(pause_event); ReleaseMutex(this_mutex);UpdateUI(); 为 QueenPanel.cpp 添加如下代码QueenPanel:QueenPanel()this-queen = NULL;n = 0;
11、queen_mutex = CreateMutex(NULL,FALSE,NULL);QueenPanel:QueenPanel(int size)this-queen = NULL;n = 0;SetSize(size);queen_mutex = CreateMutex(NULL,FALSE,NULL);QueenPanel:QueenPanel()/析构函数,释放空间if(queen!=NULL)free(queen);BEGIN_MESSAGE_MAP(QueenPanel, CWnd)/AFX_MSG_MAP(QueenPanel)ON_WM_PAINT()/AFX_MSG_MAPE
12、ND_MESSAGE_MAP()QueenPanel message handlersvoid QueenPanel:OnPaint() CPaintDC dc(this); / device context for paintingif (n = 0 | queen = NULL) return;RECT rect;GetWindowRect(CDC MemDC; /定义一个显示设备对象CBitmap MemBitmap;/定义一个位图对象WaitForSingleObject(queen_mutex, INFINITE);int w = rect.right-rect.left;int h
13、 = rect.bottom -rect.top;int board = w = h ? h : w;board = board - board % n;int cell = board / n;/System.out.println(“w:“ + w + “ h:“ + h + “ x: “ + x + “ y:“ + y + “ cell:“ +/ cell + “ board:“ + board + “ rl:“ + rl);int count = 0; int i;CPen b_pen(PS_SOLID, 1, RGB(0, 0, 255);CPen r_pen(PS_SOLID, 1
14、, RGB(255, 0, 0);CBrush y_brush, b_brush;y_brush.CreateSolidBrush(RGB(255, 255, 0);b_brush.CreateSolidBrush(RGB(255, 255, 255);MemDC.CreateCompatibleDC( /建立兼容的内存显示设备MemBitmap.CreateCompatibleBitmap(/建立一个兼容的位图CBitmap *pOldBit=MemDC.SelectObject(MemDC.FillRect(CRect(0, 0, w, h), if(cell= 0) MemDC.Elli
15、pse(queeni * cell + cell / 6, i * cell + cell / 6,queeni * cell + cell / 6+cell * 2 / 3,i * cell + cell / 6+cell * 2 / 3);count+;ReleaseMutex(queen_mutex);dc.BitBlt(0,0,w, h,void QueenPanel:DrawBoard(CDC *pDC, int size, int cell) int i, j;CBrush w_brush, b_brush;b_brush.CreateSolidBrush(RGB(0, 0, 0)
16、;w_brush.CreateSolidBrush(RGB(255, 255, 255);for(i=0; iFillRect(CRect(i*cell, j*cell, (i+1)*cell -1, (j+1)*cell-1), else pDC-FillRect(CRect(i*cell, j*cell, (i+1)*cell -1, (j+1)*cell-1), CPen b_pen(PS_SOLID, 1, RGB(0, 0, 0);int board = cell*size;pDC-SelectObject(b_pen); pDC-MoveTo(0, 0);pDC-LineTo(0,
17、 board-1);pDC-LineTo(board-1, board-1);pDC-LineTo(board-1, 0); pDC-LineTo(0, 0); void QueenPanel:SetSize(int size) WaitForSingleObject(queen_mutex,INFINITE);if(sizen) if(queen!=NULL)free(queen);queen = (int *)malloc(size*sizeof(int);for(int i=0;isize;i+)queeni = -1;n = size;ReleaseMutex(queen_mutex)
18、;RedrawWindow(); void QueenPanel:SetQueen(int *newq)WaitForSingleObject(queen_mutex,INFINITE);int i;for (i = 0; i n; i+) queeni = newqi; ReleaseMutex(queen_mutex);RedrawWindow(); void QueenPanel:SetQueen(int row, int col)WaitForSingleObject(queen_mutex,INFINITE);queenrow = col;ReleaseMutex(queen_mut
19、ex);RedrawWindow(); 在 CEightQueenDlg.cpp 中的顶部添加如下代码#include “QueenPanel.h“将 QueenPanel.h 包含进来六、测试与结论七、设计过程遇到的问题、思考及解决方法本程序主要的重点是主要是为“开始”组建添加的子程序,还有对“画板”组建类的定义和实现。开始时在对画板就行操作时遇到了些问题,黑白两色不能按要求画好,之后调整了函数的参数就可以了。八、心得体会通过为期一周的课程设计,让我进一步了解到了 visual c+中MFC 的知识,掌握了运用 C+来实现一些基本的功能软件,和在实现一个程序时所需做的准备,应先把整体框架理出
20、来,设定适当的变量和函数。在编写程序的时候要细心,有时候虽然是简单的小程序,但由于疏忽还是会照成一些错误产生。在老师给出的实验要求和目的的基础上,我们小组对其进行了一些扩充,我们最终实现的是基于人机界面可视化窗口,这个可视化界面主要的功能分为以下几部分:第一、增加了暂停单步调试的功能,能一个一个的放置皇后,在程序运行时让我们更好的理解实现该皇后问问题的基本原理即经典的回溯法。第二、我们利用画板来实现皇后的放置,并且在用画板画棋盘时我们用到了黑白两色,更加直观,便于观察排错。第三、我们在窗体中放置了一个编辑框,让我们可以随意修改 n 值。第四、我们还添加了一个不中断的单选框,即我们在输入一个 n 值后,皇后就开始不间断的放置,直到最后一种方案,在最后会弹出一个信息框,把总共我们求得的放置皇后的方案显示出来。通过此次实习我也认识到了在 C+中算法的重要性,为今后的学习奠定了基础。