递归
例题:
n皇后问题
Problem Description:
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
Input:
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
Output:
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
思路:
在全排列上进行求解,由于当达到递归边界时表示生成了一个排列,所以需要在其内部判断是否为合法方案,即遍历每两个皇后,判断他们是否在同一条对角线上,如果不是则累计计数变量count。采用枚举法
代码:
int count=0; void generateP(int index){ if(index==n+1){//递归边界,生成一个排列 bool flag=true; for(int i=1;i<=n;i++){//遍历任意两个皇后 for(int j=i+1;j<=n;j++){ if(abs(i-j)==abs(P[i]-P[j])){//如果再一条对角线上 flag=false; } } } if(flag){ count++; } return ; } for(int x=1;x<=n;x++){ if(hashTable[x]==false){ P[index]=x; hashTable[x]=true; generateP(index+1); hashTable[x]=false; } } }
回溯法:
一般来说,如果在到达递归边界前的某层,由于一些事实导致已经不需要往任何一个子问题递归,就可以返回上一层。
void generateP(int index){ if(index==n+1){//递归边界 count++; return; } for(int x=1;x<=n;x++){//第x行 if(hashTable[x]==false){//第x行没有皇后 bool flag=true;//flag为true表示当前皇后不会和之后的皇后冲突 for(int pre=1,pre<index;pre++){//遍历之前的皇后 //第index列皇后的行号x,第pre列皇后的行号为P[pre] if(abs(index-pre)==abs(x-P[pre])){ flag=false;//与之前的皇后在同一条对角线上 break; } } if(flag){//如果可以把皇后放在第x行 P[index]=x;//令第index列皇后的行号为x hashTable[x]==true;//第x行已被占用 generateP(index+1);//递归处理第index+1行皇后 hashTable[x]=false;//递归完毕,还原第x行为未占用 } } } }