1. 程式人生 > >遞迴演算法之八皇后

遞迴演算法之八皇后

八皇后問題核心:

1:同一行或者同一列不能放置皇后;

2:斜率為1/-1的對角線上不能有兩個皇后。

如圖:

實現原理:

 

 

#include<iostream>
#include<cstdio>
using std::cout;
using std::endl;
int count = 0;

int detection(int(*board)[8], int line, int row)//board:棋盤,line:行,row:列
{
    int i;
    int b1,b2;//y=kx+b
    int flag1,flag2,flag3;
    flag1 = flag2=flag3=0;//標誌變數
    //判斷列
    for (i = 0; i < 8; i++)
    {
        if (board[i][row] != 0)//判斷第第row列每行元素是否為0
        {
            flag1 = 1;//設定標誌位
            break;//退出
        }
    }
        
    //斜率為1/-1對角線判斷
    b1 = row - line;//y=kx+b
    b2 = line + row;//y=-kx+b
    for (int j = 0; j <line; j++)//遍歷行
    {
        if (flag2 == 1)//如果找到不合理情況則沒必要繼續
            break;//退出行
        for (int k = 0; k < 8; k++)//遍歷列
        {
            if (board[j][k] == 1)//檢測j行k列中資料為1的元素
            if (k - j - b1 == 0 || k + j - b2 == 0) // 如果該元素滿足該點方程則本次放置不合理(雙對角線同時檢測)
            {
                flag2 = 1;//設定標誌位
                break;//退出本次列迴圈
            }
        }
    }
    
    if (flag1 || flag2 )
        return 0;//只要有一種情況使得標誌位flag為1那麼久返回0;不滿足
    else
        return 1;//滿足返回1

}
int recursive(int(*board)[8], int line, int row)//board:棋盤,line:行,row:列  遞迴函式
{
    int board2[8][8];//臨時棋盤
    int n;//臨時列
    for (int i = 0; i < 8;i++)//拷貝傳入遞迴中的棋盤
        for (int j = 0; j < 8; j++)
            board2[i][j] = board[i][j];
    if (line == 8)//遞迴結束條件,第七行放置完畢line=8;
    {
        count++;//方法總數
        for (int i = 0; i < 8; i++)//列印每一種方法
        {
            for (int j = 0; j < 8; j++)
                cout << board[i][j] << "   ";
            cout << endl;
        }
        cout << count << endl;
    }
    else//遞迴呼叫
    {
        for (n = 0; n < 8; n++)//n:臨時列,一次窮舉每一行中符合方案的每一列的放置
        {
            if (detection(board2, line, n) != 0)//檢測是否可以放置
            {
                for (int k = 0; k < 8; k++)//將可以放的第line行其他元素清0,好處:不會存在當我們回退一級遞迴時不會出現
                    board2[line][k] = 0;   //同一行中放置兩個1,返回上一級遞迴時我們將前一次不滿足的放置清0
                board2[line][n] = 1;    //放置元素
                recursive(board2, line + 1, n);//不可用line++;line++會改變前一次的遞迴呼叫總的line這樣當有錯誤方案時line無法後退
            }                         //line+1:前一級的遞迴函式中的line沒有被改變
        }
    }
    return 0;
}
void main()
{
    int board[8][8] = { 0 };
    int line=0;//行
    int row=0;//列
    recursive(board, line, row);
    system("pause");
}
 

 

 

 

 轉載請標明原貼出處:https://blog.csdn.net/zj490044512