状态变化树是一颗满二叉树,树中每个叶子结点的状态都是求解过程中可能出现的状态(即问题的解)。然而很多问题用回溯和试探求解的时候,描述求解过程的状态不是一颗满二叉树。也就是说只有部分叶子结点的状态才是解的状态,这就要要求在回溯的过程中当试探出现的状态和解的状态出现矛盾的时候,就不再继续往下试探了。这类问题的求解过程可以看作在约束条件下进行先根遍历,并在遍历过程中修剪掉那些不满足条件的分支。
八皇后问题就是这样一类很经典的问题:
#include <iostream>
#include <math.h>
using namespace std;
typedef struct{ //记录皇后位置的结构体
int x;
int y;
bool flag;
}Queen;
Queen *mqueen;
int result_num = 0;
void OutputState(int n) { //输出皇后在棋盘上的位置,#表示皇后
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if(mqueen[i].y == j)
cout<<" # ";
else
cout<<" 0 ";
}
cout<<endl;
}
cout<<endl;
}
void Trial(int k,int n){ //递归回溯遍历所以结果
if(k == n){
OutputState(n);
result_num++;
}else{
mqueen[k].x = k;
for(int i = 0; i < n; i++){
mqueen[k].y = i;
mqueen[k].flag = true;
for(int j = 0; j < k; j++){ //肯定不在同一行
if(mqueen[j].y == mqueen[k].y //判断是否在同一列或者在对角线上
|| abs(mqueen[j].x - mqueen[k].x)
== abs(mqueen[j].y - mqueen[k].y)){
mqueen[k].flag = false;
break;
}
}
if(mqueen[k].flag){ //对不满足条件的状态停在遍历,也就是对二叉树状态结点的修枝
Trial(k+1,n);
}
}
}
}
int main(){
int num;
cin>>num; //输入皇后的个数
mqueen = new Queen[num];
Trial(0,num);
cout<<result_num<<endl; //输出解的个数
}