演算法-N皇后問題
2018/9/23
N皇后問題:在NxN的棋盤上,放置N個棋子, 使得同一行、同一列、同一對角線上只有一個棋子,問有多少種滿足條件的放置方法?
回溯法和位運演算法
方法1: 【回溯法】 回溯法也叫試探法,她是一種系統地搜尋問題的解的方法。
回溯法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。
回溯法是解決一種問題的“萬能演算法”,這種問題是:需要將所有可能情況都窮舉出來,然後從中找出滿足某種要求的可能情況或最優解,從而得到整個問題的解。
/******
* 非遞迴方法的一個重要問題時何時回溯及如何回溯的問題。
程式首先對N行中的每一行進行探測,尋找該行中可以放置皇后的位置,具體方法是對該行的每一列進行探測,看是否可以放置皇后,
如果可以,則在該列放置一個皇后,然後繼續探測下一行的皇后位置。如果已經探測完所有的列都沒有找到可以放置皇后的列,
此時就應該回溯,把上一行皇后的位置往後移一列,如果上一行皇后移動後也找不到位置,則繼續回溯直至某一行找到皇后的位置或回溯到第一行,
如果第一行皇后也無法找到可以放置皇后的位置,則說明已經找到所有的解程式終止。
如果該行已經是最後一行,則探測完該行後,如果找到放置皇后的位置,則說明找到一個結果,打印出來。
但是此時並不能再此處結束程式,因為我們要找的是所有N皇后問題所有的解,此時應該清除該行的皇后,從當前放置皇后列數的下一列繼續探測。
*
*回溯法解N皇后問題
*使用一個一維陣列表示皇后位置a[N]
*其中陣列的下標表示皇后所在的行row, 陣列元素值表示皇后所在的列
*這樣設計的棋盤,所有皇后必定不在同一行,所以行衝突是不存在的
*********/
#include <stdio.h>
#include <iostream>
#include <math.h> //判斷同一對角線上是否有衝突
using namespace std;
#define N 8 //皇后的數目
#define INIT -100 //棋盤的初始值(儘可能小的負數),因為a[i]取值從0~N-1
int a[N]; //用一維陣列表示棋盤
void queue_init()
{
for (int i = 0; i < N; i++)
{
a[i] = INIT;
}
}
bool judge_queue_valid(int row, int col)
{
for (int i = 0; i < N; i++)
{
if (a[i] == col || abs(row - i) == abs(col - a[i])) //如果列衝突或者對角線衝突,則無效
{
return false;
}
}
return true;
}
int queue_core()
{
int i = 0, j = 0; //i表示row行號,j表示col列號
int n = 0; //可行的放置方案數
while (i < N)
{
while (j < N) //對i行中的每一列進行探測,看是否可以放置皇后
{
if (judge_queue_valid(i, j)) //判斷放置此處是否滿足N皇后條件
{
a[i] = j; //滿足條件在i行j列放置皇后
j = 0; //因為下一行又要從第一列開始遍歷判斷,所以列清零
break; //退出內迴圈
}
else //i行j列這個位置不滿足N皇后條件
{
j++; //繼續在此行下一列探測,直到此行最後一個位置探測完自然退出內迴圈
}
}
//i行的所有N列已經探測完了,此處判斷是否找到了滿足條件的位置
if (INIT == a[i]) //如果此行沒有滿足條件的,則需要回溯,回溯是從後往前依次重新判斷
{
if (0 == i) //i==0,回溯到最後依次:說明剛剛的內迴圈是在第一行中尋找滿足條件的解,但是可惜沒有找到
{
break; //找完了所有滿足條件的解,退出大迴圈
}
else //不是最開始的一行,則往上回溯
{
i--; //回溯到上一行
j = a[i] + 1; //從上一次滿足條件的下一個位置resume judge
a[i] = INIT; //把上一行皇后的位置清除,重新探測
continue; // 設定好j後,重新開始內迴圈
}
}
//如果a[i]不是初始值,則說明i行a[i]列滿足條件,則繼續往下執行
if ( N - 1 == i) //i探測的結果是最後一行
{
n++; //滿足的方案數目
j = a[i] + 1; //從最後一行放置皇后的下一列進行回溯探測
a[i] = INIT; //清除最後一行的皇后位置
continue;
}
i++; //如果第i行滿足條件,並且不是最後一行,則繼續探測下一行
}//end while(i<N)
return n;
}
int main()
{
int solution_count = 0;
queue_init();
solution_count = queue_core();
cout << solution_count << endl;
system("pause");
return 0;
}
方法1: 【位運演算法】 --未完待續。。。
位運算基本操作的意義: