N-Queens(递归回溯+迭代回溯)

来源:互联网 发布:祥南行书体 mac 编辑:程序博客网 时间:2024/06/07 20:54

回溯法算法思想:

 回溯法在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树;
 算法搜索至解空间树的任一节点时,先判断该节点是否包含问题的解;
 如果肯定不包含,则跳过对以该节点为根的子树的搜索,逐层向其祖先节点回溯;
 否则,进入该子树,继续按深度优先策略搜索。

回溯法解题模板:

 针对所给问题,定义问题的解空间;
 确定解空间结构;
 以深度优先方式搜索解空间;
 按约束条件进行剪枝。

总结递归回溯模板和迭代回溯模板:

/*递归回溯模板*/void backtrack(){    if(t>n)  //t表示递归深度,n控制递归深度。t>n表示算法已搜索至叶节点        output(x);  //记录或输出得到的可行解x    else    {        //f(n,t)和g(n,t)分别表示在当前扩展结点处未搜索过的子树的起止编号和终止编号        for(int i=f(n,t);i<=g(n,t),i++)            {            x[t]=h(i);   //h(i)表示在当前扩展结点处x[t]的第i个可选值            if(constraint(t) && bount(t)) //当前扩展结点处的约束函数和限界函数            backtrack(t+1);        }    }}/*迭代回溯模板*/void iterativeBacktrack(){    int i=1;    while(t>0)    {        if(f(n,t)<=g(n,t))        {            for(int i=f(n,t);i<=g(n,t);i++)            {                x[t]=h(i);                if(constraint(t) && bount(t))                {                    if(solution(t)) //判断在当前结点处是否已得到问题的可行解                        output(x);                    else                        t++;                }            }        }        else t--;    }}

N-Queens

Problem Description
The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.In the N*N square checkerboard, the N queens are placed so that they do not attack each other (that is, any 2 queens are not allowed in the same row, the same column, nor in a diagonal line with the 45 corners of the checkerboard frame.

Your task is to find out how many legitimate placement methods are available for a given N.

这里写图片描述
Given an integer n, return all distinct solutions to the n-queens puzzle.

For example,
There exist two distinct solutions to the 4-queens puzzle:

Input
There are a number of lines, each line is a positive integer less than or equal to 20 N, the number of the chessboard and the queen.

Output
Each row has a positive integer indicating the number of queens placed for the corresponding input line.

Sample Input
4

Sample Output
2

题目分析及思路:

棋盘类的题目一般是回溯法。

 定义解空间(解的取值范围):
用一个n元向量X=(x1,x2,…..xn)表示,其中,1≤ i≤ n且1≤ xi≤ n,即第n个皇后放在第i行第xi列上。

 确定解空间结构
以4皇后为例。
这里写图片描述

 定义约束条件
该题有两个约束:一是不允许2个皇后放在同一列,所以解向量中的x[i]互不相同;二是2个皇后不能放在同一斜线上,这是问题的隐约束。
所以要将这一隐约束化成显约束:盘左上角到右下角的主对角线及其平行线(斜率为-1的各斜线)上,2个下标值的差(行号-列号)值相等;同理斜率为+1的每条斜线上2下标值的和(行号+列号)相等。所以2个皇后放置位置分别是(I,j)和(k,l)且i-j=k-l或i+j=k+l时表示2个皇后处于同一斜线上。即是|i-k|=|j-l|,隐约束就化成了显约束。

 用DFS搜索解空间,并按约束条件剪枝,加快搜索速度

算法实现:

递归回溯解题:

#include<iostream>using namespace std;#define N 20int x[N],n,sum=0; //皇后放置列数、个数、可行解个数bool place(int k){    for(int j=1;j<k;j++)    {        if(x[j] == x[k] || abs(x[j]-x[k]) == abs(k-j))            return false;    }    return true;}int backtrack(int k){    int i=0;    if(k>n)     {        sum++;     }    else    {        for(i=1;i<=n;i++)            {            x[k]=i;              if(place(k))            backtrack(k+1);        }        return sum;    }}int main(){    printf("请输入皇后个数(n<20):");    scanf("%d",&n);    printf("放置方法数为:%d\n:",backtrack(1));    return 0;}

迭代回溯解题:

/*迭代回溯*/#include<iostream>using namespace std;#define N 20int x[N],n,sum=0; //皇后放置列数、个数、可行解个数bool place(int k){    for(int j=1;j<k;j++)    {        if(x[j] == x[k] || abs(x[j]-x[k]) == abs(k-j))            return false;    }    return true;}int backtrack(){    int k=1;    x[1]=0;    while(k>0)     {        x[k]++;         //当前列加1的位置开始搜索        while(x[k]<=n && !place(k))  //当前位置是否满足条件            x[k]++;    //不满足继续搜索下一位置        if(x[k]<=n)        {              if(k==n)   //最后一个皇后,完成搜索                sum++;            else       //不是则继续处理下一个皇后                x[++k]=0;          }          else           //回溯            k--;    }    return sum;}int main(){    printf("请输入皇后个数(n<20):");    scanf("%d",&n);    printf("放置方法数为:%d\n",backtrack());    return 0;}
原创粉丝点击