1. 问题描述:在n×n的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n皇后问题等价于在n×n的棋盘上放置n个皇后,任何2个皇后不能放在同一行或同一列或同一斜线上。
2. 问题分析:
用n元数组x[n]表示问题的解。其中x[i]表示皇后i放在棋盘第i行第x[i]列。由于不允许将2个皇后放在同一列上,所以解向量中的x[i]互不相同,
2个皇后不能放在同一斜线上是问题的隐约束。设2个皇后的放置位置分别是(i,j)和(k,l),则如果满足|i-k|=|j-l|,就表明2个皇后位于同一条斜线上。
分析可知,解空间树是完全n叉树,剪枝函数剪去不满足行、列、斜线约束的子树。
#include <iostream> #include <cmath> using namespace std; int N=5; int x[5]; //可行解 int sum=0;//可行解数量 bool Place(int k) { for(int i=0; i<k; i++) { if(abs(k-i)==abs(x[i]-x[k])||x[i]==x[k])return false; } return true; } void Backtrack(int t) //递归回溯 { if(t>=N) { sum++;//到达叶子结点,即找到了一个新的可行解,则解的数量sum++; for(int i=0; i<N; i++) { cout<<x[i]<<" "; } cout<<endl; } else { for(int i=0; i<N; i++) { x[t]=i; if(Place(t))Backtrack(t+1); } } } void Backtrack2() //迭代回溯 { x[0]=0; int k=0; while(k>=0) { while(x[k]<N&&Place(k)==false)x[k]+=1; if(x[k]<N) { if(k==N-1) //到了叶子结点,输出一个解,回溯 { sum++; for(int i=0; i<N; i++) { cout<<x[i]<<" "; } cout<<endl; k--; x[k]+=1; } else //没到叶子结点继续往下走 { k++; x[k]=0; } } else //说明当前行无法放置,回溯 { k--; x[k]+=1; } } } int main() { //Backtrack(0); Backtrack2(); /*0 2 4 1 3 0 3 1 4 2 1 3 0 2 4 1 4 2 0 3 2 0 3 1 4 2 4 1 3 0 3 0 2 4 1 3 1 4 2 0 4 1 3 0 2 4 2 0 3 1*/ }
3.时间复杂度:最坏时间复杂度Place方法O(n),所以Backtrack方法时间复杂度为O(n^3);