1. 程式人生 > >用棧實現八皇后問題

用棧實現八皇后問題

    國際象棋中皇后勢力的範圍是其所在位置的水平線、垂直線以及兩條對角線。就像下面這樣

                                                                    

    其中的  9 就表示皇后,其中的  1  表示皇后的勢力範圍。於是就產生了一個問題,在 n * n 的一個棋盤上,最多隻能放置 n 個皇后使得他們不能互相攻擊。解決這個問題的方式可以為先放置一個皇后在(0,0)處,之後在下一排下一位放置下一個皇后,不行的話再向後挪一位,然後再向下一排放置下一個皇后,但是當某一排皇后找不到合適位置時,就回到上一排,再挪動上一個皇后,一直到  n 個皇后放置完。這其中最主要的就是遞迴的呼叫以及棧的特性的使用。具體實現程式碼如下:

// ConsoleApplication1.cpp : 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
#include<cmath>
using namespace std;
#define StackSize 8 /*最多放8個皇后*/
int queen[StackSize][StackSize] = { 0 }; /*棋盤*/
int ans = 0;                           /*解數*/
int top = -1;                          /*棧頂指標*/
int datas[8];                  /*儲存皇后位置*/
									  /*入棧*/
void Push(int x)                                          //入棧操作
{
	top++;                                                           //棧頂指標上移
	datas[top] = x;
}
/*出棧*/
void Pop()                                              //出棧操作
{
	top--;                                                           //棧頂指標下移
}

void SeqStack() { top = -1; }                                              //建構函式,初始化空棧
																		   /*放N皇后的遞迴函式*/
void PlaceQueen(int row)                                //在棧頂放置符合條件的值的操作,即擺放皇后
{
	bool Judgement();
	void SeqStack();                                    //關鍵點1:每一次擺放都會初始化空棧
	void Output();
	for (int col = 0; col<StackSize; col++)                              //窮盡0~7,即窮盡列
	{
		Push(col);
		if (Judgement())                                             //判斷擺放皇后的位置是否安全
		{
			if (row<StackSize - 1)                                     //若還沒有放到第八個皇后,則進行下一個皇后的放置
				PlaceQueen(row + 1);
			else
			{
				ans++;                                               //解數加1
				Output();                                            //列印成功的棋盤
			}
		}
		Pop();                                                       //若不符合條件則出棧        
	}
}

/*關鍵點2:判斷合法性*/
bool Judgement()
{
	for (int i = 0; i<top; i++)                                           //依次檢查前面各行的皇后位置
		if (datas[top] == datas[i] || (abs(datas[top] - datas[i])) == (top - i))    //判斷是否在同一列同一斜線
			return false;                                            /*第一個條件,使每次入棧的數字不同層(行)*/
	return true;                                                     /*top-i的值就是皇后之間的非法相對距離,值為0、1、2....,也就是同一條對角線或者斜對角線。data[top]-data[i]為2個皇后的實際的相對距離。*/
}

/*輸出棋盤*/
void Output()                                          //將棧的陣列形式列印成棋盤形式
{
	cout << "NO." << ans << ":" << endl;
	for (int i = 0; i<StackSize; i++)
	{
		for (int j = 0; j<datas[i]; j++)
			cout << "- ";                                             //不放置處列印“-”
		cout << "Q";                                                  //放置處列印“Q”
		for (int j = StackSize - 1; j>datas[i]; j--)
			cout << " -";
		cout << endl;                                                 //換行
	}
	cout << endl;
}
int main()
{
	PlaceQueen(0);                                        //從棧底開始賦值
	cout << "the total number of solutions is:" << ans << endl;       //輸出擺放方法的總數
	system("pause");
	return 0;
}

我自己試著用棧再寫了一下,但是主要還是借鑑了大佬,在此表示感謝。

另外大佬的原始碼在VS2015上會報錯,“data 不明確的符號”,我查了一下是因為在VS的函式庫中有 data ,所以編譯器會不確定我們所寫的data是庫中的data還是定義的全域性變數,所以就報錯了。解決辦法就是用::來表明使用的是庫函式,當然更簡單的就是直接改個變數名。