用棧+回溯+非遞迴解決N皇后問題

kewlgrl發表於2016-04-05

問題及程式碼:

/*
* Copyright (c) 2016, 煙臺大學計算機與控制工程學院
* All rights reserved.
* 檔名稱:queen.cpp
* 作    者:單昕昕
* 完成日期:2016年4月4日
* 版 本 號:v1.0
*/
#include <iostream>
#include <malloc.h>
#include <cstdio>
#include <cmath>
using namespace std;
const int MaxSize=400;

typedef struct linknode//順序棧
{
    int data[MaxSize];
    int top;
} SqStack;
SqStack *st;

void initStack(SqStack *&s)//初始化
{
    s=(SqStack *)malloc(sizeof(SqStack));
    s->top=-1;
}

bool Push(SqStack *&s,int e)//壓入棧
{
    if(s->top==MaxSize-1)
        return false;
    s->top++;
    s->data[s->top]=e;
    return true;
}

bool Pop(SqStack *&s)//移除棧頂元素
{
    if(s->top==-1)
        return false;
    s->top--;
    return true;
}

bool GetTop(SqStack *s,int &e)//取棧頂元素
{
    if(s->top==-1)
        return false;
    e=s->data[s->top];
    return true;
}

bool StackEmpty(SqStack *s)//判斷棧是否為空
{
    return(s->top==-1);
}

void DestroyStack(SqStack *&s)//銷燬棧
{
    free(s);
}

bool Check(int *qu, int t)//能放返回真,否則為假
{
    int i;
    for(i=0; i<t; i++)//逐行判斷
        if(qu[i]==qu[t]||abs(t-i)==abs(qu[t]-qu[i]))//在同一列或對角線
            return false;
    return true;
}

void Show(int *qu, int len,int Count)
{
    int i;
    cout<<"第"<<++Count<<"個解:";
    for(i=0; i<len; i++)//i是行數
        cout<<"("<<i<<", "<<qu[i]<<") ";
    cout<<endl;
}

int main()
{
    initStack(st);//初始化
    cout<<"皇后問題(n<20) n=";
    int n;
    cin>>n;//輸入皇后數目
    cout<<n<<"皇后問題求解如下:"<<endl;
    int cnt=0,row=0;//問題的解的數目、行
    int *queen = new int[n];//開闢動態陣列儲存每行皇后的列位置
    queen[0]=-1;//最開始把首元素置為-1
    Push(st,0);//把首位置壓入棧
    while(!StackEmpty(st))//棧非空
    {
        GetTop(st,row);//row是當前棧頂元素值
        queen[row]++;//嘗試下一列
        if(queen[row]>=n)//當前行的所有n列都已經嘗試過,但是皇后沒有擺放成功
            Pop(st);//棧頂元素出棧,相當於回溯到上一行
        else
        {
            if(Check(queen,row))//檢查,如果能在該位置放皇后
            {
                if(row==n-1)//試探到第n行
                {
                    Show(queen,n,cnt);//輸出皇后位置
                    cnt++;//解法加一
                }
                else//仍需要試探
                {
                    queen[row+1]=-1;//標記-1
                    Push(st,row+1);//皇后的位置壓入棧
                }
            }
        }
    }
    delete []queen;//釋放動態陣列
    free(st);//銷燬棧
    return 0;
}

執行結果:




思路:

queen[row]陣列記錄第row行上皇后的列位置;

st棧記錄當前行數;

從第0行開始,依次試探0-n-1列;

當row==n-1說明全部成功放置皇后;

當queen[row]>=n說明當前行下,各列試探完畢,都不能成功放置,所以要回溯到上一行,將當前行出棧。

相關文章