先上代碼
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
using namespace std;
vector<int> board;
void ShowQueen(void)
{
for(unsigned int i = 0; i < board.size(); i++)
{
cout << "(" << i << "," << board[i] << ") ";
}
cout << endl;
}
bool isValid(int rows, int cols, int order)
{
if(rows >= order || cols >= order)
return false;
for(int i = 0; i < rows; i++)
{
if(cols == board[i])
return false;
else if(abs(cols-board[i]) == abs(rows-i))
return false;
}
return true;
}
int QueenMutex(int k)
{
if(k <= 3)
return 0;
int solutions = 0;
board[0] = 0;
int row = 1;
int col = 0;
while(row != -1)
{
if(isValid(row, col, k))
{
board[row] = col;
if(row == k-1)
{
solutions++;
ShowQueen();
row--;
col = board[row]+1;
}
else
{
row++;
col = 0;
}
}
else
{
col++;
if(col >= k)
{
row--;
col = board[row]+1;
}
}
}
return solutions;
}
int main(int argc, char const *argv[])
{
int order = 4;
if(argc == 2)
{
order = atoi(argv[1]);
if(order <= 0)
{
order = 4;
}
}
board.assign(order, 0);
int n = QueenMutex(order);
cout << "solutions: " << n << endl;
return 0;
}
可以由參數指定要解決問題的規模N,我在ubuntu14.04 64bitOS下模擬出來,一共有92個解,時間10ms左右。
問題需求描述:在一個N×N的二維棋盤內,每行放置一個皇后,使得他們不能相互攻擊。
轉化:由皇后的走法規則直接將問題直接轉化爲任意兩個皇后不能在同一行或同一列或任意45°角斜線上。
思考的問題1:棋盤和皇后的位置怎麼表示?
之前一直想的是用一個N*N的二維數組表示,畢竟這樣比較直觀。後來發現這樣不僅浪費空間,而且也會浪費時間。
一種比較好的辦法是:用一個1×N的1維數組表,第i行的元素的值表示該行皇后所在的位置,行與行之間自然分開。
全局容器board用來存放皇后的位置。
思考的問題2:思路
利用窮舉法和回溯法,將每一種可能的組合都嘗試一邊,符合要求的就輸出,否則回到上一行皇后的下一個位置開始繼續嘗試。因此只要寫出判斷一個皇后的位置是否合法,即可比較清晰地理解思路。該函數爲bool isValid(int rows, int cols, int order);若該皇后符合要求,將其位置放到相應的board元素中board[row] = col; 並判斷皇后是否已經全部放置好,若是則輸出,進而再回到上一行嘗試其他組合(line45---50),若不是,則將row加1,進入下一行的判斷。若該皇后不符合要求, 將列數加1,繼續判斷。同時要判斷是否到達邊界,若是則返回上一行繼續嘗試(line61---64)。這就是所謂的回溯。本題中由於要找到所有的解,所以不管是找到滿足要求的解,還是發現當前組合不能滿足時,都要進行回溯。如果只要求找到一種解,則對前一種情況返回即可,而後一種情況仍需回溯。