递归

例题:

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行为未占用 
            }
        }
    }
}

 

posted @ 2020-08-09 11:04  Heinrich♣  阅读(105)  评论(0编辑  收藏  举报