回溯法与N皇后问题

回溯法

回溯法是用来解决这样的问题:在相对于问题的输入规模按照指数速度增长的域中,找出一个具有指定特性的元素,如在图顶点的所有排列中求一个哈密顿回路,或者背包问题。

回溯法实际上是对穷举查找的优化 。它通过对所做的选择构造一颗所为的空间状态树来实现。具体来说,树的根节点表示在查找前的初始状态,树的第一层节点表示对解得第一个分量做的选择,以此类推。如果一个部分的构造解仍然有可能导致一个完整解,我们就说这个部分解在树中的相应节点是有希望的,否则就是无希望的。叶子节点则要么代表没希望的死胡同,要么代表算法的完整解。如果当前节点是有希望的,则向部分解添加下一个分量的第一个合法选择,进而将问题转向下一层的子女节点。如果当前节点无希望了,则回溯到其父母节点,考虑下一个可能选择。如果选择不存在,则继续回溯。直到找到完整解为止。

下面用N皇后问题来具体解释:

N皇后问题

从空棋盘开始,把皇后1放在第一行第一列。然后放皇后2,1、2列尝试失败,把它放在第三个位置,即格子(2,3),但是这被证明是一个死胡同,因为皇后三将无位置可以放,因此皇后2回溯到(2,4),这样皇后3可以放到(3,2),但是这又是另一个死胡同。就这样不断的向下试探,不行就回溯到上层,直到找到最终的完整解。以下给出4皇后的状态空间树:

具体实现:

把棋盘存储为一个N维数组a[N],数组中第i个元素的值代表第i行的皇后位置,这样便可以把问题的空间规模压缩为一维O(N),在判断是否冲突时也很简单,首先每行只有一个皇后,且在数组中只占据一个元素的位置,行冲突就不存在了,其次是列冲突,判断一下是否有a[i]与当前要放置皇后的列j相等即可。至于斜线冲突,通过观察可以发现所有在斜线上冲突的皇后的位置都有规律即它们所在的行列互减的绝对值相等,即| row – i | = | col – a[i] | 。这样某个位置是否可以放置皇后的问题已经解决。
 

 【C语言代码】

#include<stdio.h>
#include<stdlib.h>

#define queen_count 8

int queen[queen_count],solution = 0;

void show(){
    printf("(");
    for(int i = 0;i < queen_count; ++i){
        printf(" %d",queen[i] + 1);
    }
    printf(")\n");
}

bool isvalid(int n){
    int i;
    for(int i = 0;i < n; ++i){//这里只需要判断n之前的行和n这一行是否有冲突
        if(queen[i] == queen[n] || abs(queen[i]-queen[n]) == abs(i-n))//当之前某行已经占了这一列,或者两个皇后在同一对角线时则冲突
            return false;
    }
    return true;
}

void put_queen(int n){

    for(int i = 0;i < queen_count;++i ){//每次从左向右试探性的找这一行皇后的位置
        queen[n] = i;
        if(isvalid(n)){//这次试探成功
            if(n == queen_count-1){
                show();
                solution++;
            }
            else{
                put_queen(n+1);
            }
        }
    }
}


int main()
{
	put_queen(0);
    printf("%d",solution);
	return 0;
}

【C++代码】

class Solution {
public:
    
    int totalNQueens(int n) {
        int solution = 0;
        vector<int> queen(n,-1);
        put_queen(solution,queen,0);
        return solution;
    }
    bool isvalid(vector<int>& queen,int row){
        for(int i = 0; i < row; ++i){
            if( queen[i] == queen[row] || abs(i-row) == abs(queen[i]-queen[row]) )
               return false;
        }
        return true;
    }
    void put_queen(int &solution,vector<int>& queen,int row){
        int n = queen.size();
        for(int i = 0; i < n; ++i){
            queen[row] = i;
            if(isvalid(queen,row)){
                if( row == n - 1 ){
                    solution++;
                }
                else{
                    put_queen(solution,queen,row+1);
                }
            }
        }
    }
};

猜你喜欢

转载自blog.csdn.net/zpznba/article/details/88926462