無解 最初接觸N皇后問題,對於N皇后問題所牽涉的回溯算法一律不知,大腦處於混沌狀態。算法
窮舉法 使用窮舉法,先把N皇后在棋盤上的排布的全部狀況都列舉出來,經過遞歸程序實現,再定義一個判斷函數,從中挑選出合適的答案。 代碼:函數
/*獲得全部的排布請款*/ void putQueens(vector<Chessboard>& chessBoards,Chessboard& chessBoard,int queensNum,int nth){ if (nth == 0){ if (isOk(chessBoard)){ chessBoards.push_back(chessBoard);//從結果中進行篩選 } } else for (int i = 0;i < queensNum;++i){ chessBoard[nth - 1][i] = 'Q'; putQueens(chessBoards,chessBoard,queensNum,nth - 1); chessBoard[nth - 1][i] = '.'; } } vector<vector<string> > solveNQueens(int n) { vector<vector<string> > chessBoards; vector<string> chessBoard; string tmp(n,'.'); for (int i = 0;i < n;++i){ chessBoard.push_back(tmp); } putQueens(chessBoards,chessBoard,n,n); return chessBoards; } bool isOk(vector<string> & queens)//對棋盤排布進行判斷,注意這裏是直接對整個棋盤進行判斷 { vector<Point> locations; vector<bool> isRepeatOnY(queens.size(),false); for (int i = 0;i < queens.size();++i) { for (int j = 0;j < queens.size();++j) { if (queens[i][j] == 'Q') { locations.push_back(Point(i,j)); isRepeatOnY[j] = true; } } } for (const auto &i : isRepeatOnY) if (!i) return false; for (int i = 1;i < locations.size();++i) { for (int j = 0;j < i;++j) if (abs(locations[i].getY() - locations[j].getY()) == abs(locations[i].getX() - locations[j].getX())) { return false; } } return true; } };
以上是用窮舉法獲得的程序,運行效率很是低,當計算8皇后問題時,在個人筆記本上須要2分鐘,而在leetcode平臺上,直接由於超時而爲經過。佈局
void putQueens(vector<Chessboard>& chessBoards,Chessboard chessBoard,int queensNum,int nth){ if (nth == queensNum){ if (isOk(chessBoard)){ chessBoards.push_back(chessBoard); } } else{ chessBoard.push_back(string(queensNum,'.')); for (int i = 0;i < queensNum;++i){ chessBoard[nth][i] = 'Q'; if (!isOk(chessBoard)){ chessBoard[nth][i] = '.';//在每種狀況產生的過程當中進行判斷 continue; } putQueens(chessBoards,chessBoard,queensNum,nth + 1); chessBoard[nth][i] = '.'; } } } vector<vector<string> > solveNQueens(int n) { vector<vector<string> > chessBoards; vector<string> chessBoard; putQueens(chessBoards,chessBoard,n,0); return chessBoards; } bool isOk(vector<string> & queens) { vector<Point> locations; for (int i = 0;i < queens.size();++i){ for (int j = 0;j < queens[i].size();++j){ if (queens[i][j] == 'Q'){ locations.push_back(Point(i,j)); } } } for (int i = 1;i < locations.size();++i){ for (int j = i - 1;j >= 0;--j){ if (locations[i].getY() == locations[j].getY() || abs((locations[i].getY() - locations[j].getY())) == abs((locations[i].getX() - locations[j].getX()))) return false; } } return true; } };
回溯法直接讓個人代碼經過了leetcode的測試,運行時間爲107ms。測試
bool isOk(Chessboard chessBoard,QueenPoint pos)//最初的判斷函數直接判斷整個棋盤,如今直接向其傳入皇后位置的座標 { int size = chessBoard[0].size(); for (int i = 0;i < pos.getX();++i){ for (int j = 0;j < size;++j){ if (chessBoard[i][j] == 'Q'){ if (pos.getY() == j || (abs(pos.getX() - i) == (abs(pos.getY() - j)))) return false; } } } return true; }
putQueens函數的聲明變爲:優化
void putQueens(vector<Chessboard>& chessBoards,Chessboard &chessBoard,int queensNum,int nth);
優化後程序的運行時間降至67ms。code
bool isValid(QueensPos points,int n){ for (int i = 0;i < n;++i){ if (points[n] == points[i] || (n - i) == abs(points[n] - points[i])) return false; } return true; } void putQueens(vector<vector<string> > &queens,QueensPos& points/*由於不須要在函數中進行push_back操做,這裏傳入引用*/,int t,int m,int n){ if (m == 0){ vector<string> tmp; for (int i = 0;i < n;++i){ string tmpStr(n,'.'); tmpStr[points[i]] = 'Q'; tmp.push_back(tmpStr); } queens.push_back(tmp); } else { for (int i = t;i < n;++i){ /*如下產生全排列*/ swap(points[i],points[t]); if (!isValid(points,t)){//回溯法進行判斷 swap(points[i],points[t]); continue; } putQueens(queens,points,t + 1,m - 1,n); swap(points[i],points[t]); } } } class Solution{ public: vector<vector<string> > solveNQueens(int n){ QueensPos queens(n); for (int i = 0;i < n;++i) queens[i] = i; vector<vector<string> > result; putQueens(result,queens,0,n,n); return result; } };
由此,程序的運行時間降至16ms。對象