大名鼎鼎的八皇后问题。相信大家都耳熟能详。
八皇后的是一个典型的用回溯法求解的问题。在回溯法中的一个关键是要动态保存求解空间对应的程序所处的状态,特别是能够进行状态“回滚”。当一发现个部分解再往下去不能成为合法的解时,要回溯到这个部分解之前所处的状态。
程序状态的“前进”和“回滚”用Ban和UnBan函数来实现。
//ban the column,row,diagonal elements of the queen void Ban(int (*p)[lenth],int m,int n) { //In fact,we need only ban elements below the queen's line 'cause\ our search is line by line if(m>=lenth-1||n>=lenth) return; //column for(int i=m+1;i<lenth;++i) ++p[i][n]; //diagonal for(int delta=1;m+delta<lenth;++delta){ if(n+delta<lenth) ++p[m+delta][n+delta]; if(n-delta>=0) ++p[m+delta][n-delta]; } } void UnBan(int (*p)[lenth],int m,int n) { //In fact,we need only unban elements below the queen's line 'cause\ our search is line by line //column for(int i=m+1;i<lenth;++i) --p[i][n]; //diagonal for(int delta=1;m+delta<lenth;++delta){ if(n+delta<lenth) --p[m+delta][n+delta]; if(n-delta>=0) --p[m+delta][n-delta]; } }
然后就是要递归遍历整个求解空间。
void DoQueenPussleR(int lineNum,int (*matrix)[lenth],int result[lenth],int& count) { if(lineNum==lenth){ for(int i=0;i<lenth;++i) cout<<result[i]<<" "; cout<<endl; ++count; } for(int i=0;i<lenth;++i) if(matrix[lineNum][i]==OK) { Ban(matrix,lineNum,i); result[lineNum]=i; DoQueenPussleR(lineNum+1,matrix,result,count); UnBan(matrix,lineNum,i); } } int QueenPussleR() { int count=0; int matrix[lenth][lenth]; int result[lenth]; for(int i=0;i<lenth;++i) for(int j=0;j<lenth;++j){ matrix[i][j]=OK; } DoQueenPussleR(0,matrix,result,count); return count; }
遗憾的是,过度的递归会造成栈溢出。以上的代码,但lenth超过了8后。就提示栈溢出了。可用栈来编写非递归的版本。非递归的版本一直适用于lenth较大的情况。
void disp(stack<int> stk) { while(!stk.empty()){ cout<<stk.top()<<" "; stk.pop(); } cout<<endl; }
int QueenPussle() { int matrix[lenth][lenth]; stack<int> choices; int i,j; int obsolete=-1; for(i=0;i<lenth;++i) for(j=0;j<lenth;++j) matrix[i][j]=OK; int size_=0; int answerNum=0; while(1){ choices.push(obsolete+1); ++size_; //test if the new choices is right if(matrix[size_-1][choices.top()]==OK){ //We need reset obsolete. obsolete=-1; Ban(matrix,size_-1,choices.top()); if(size_!=lenth) continue; else{ ++answerNum; disp(choices); } } //Notify the upper line to chose next one of obsolete obsolete=choices.top(); choices.pop(); --size_; //obsolete==lenth-1 means: this is no available one to choose in this line while(obsolete==lenth-1){ UnBan(matrix,size_-1,choices.top()); obsolete=choices.top(); choices.pop(); --size_; if(size_==0&&obsolete==lenth-1) return answerNum; } } }
最后是主程序:
int _tmain(int argc, _TCHAR* argv[]) { clock_t start_,clicks1,clicks2; start_=clock(); cout<<QueenPussle()<<endl; clicks1=clock()-start_; start_=clock(); cout<<QueenPussleR()<<endl; clicks2=clock()-start_; cout<<"Time consumed by irrecursive way:"<<endl; cout<<static_cast<double>(clicks1)/static_cast<double>(CLOCKS_PER_SEC)<<endl; cout<<"Time Consumed by recursive way:"<<endl; cout<<static_cast<double>(clicks2)/static_cast<double>(CLOCKS_PER_SEC)<<endl; return 0; }
奇怪的是,照理说非递归的版本应该比递归的要快。可我的测试中,从4-8都是递归的版本快(超过8,就只有非递归的运行有效了)。我只能说,STL,你太不给力了。