N皇后问题递归与非递归解法

问题描述:

一个n*n的棋盘,要在上面放n个皇后。规则:两个皇后之间如果是同列、同行、同对角线它们会互相攻击。也就是说:棋盘上的任意两个皇后皇后

不能为同列、同行、同对角线。

 

问题分析

对于这个问题、当n不大的时候,可以用穷举法实现。对于n皇后,每一行有n个位置可以放,一共n行。就会有n的n次方种情况。对于这些情况、再一一判断是不是满足情况。

其实一个关键的点在于:什么时候判断已经放了皇后的棋盘是否满足条件,大致可以分为两种:

1、等棋盘上放了n个皇后以后判断

2、放一个皇后判断一次、对于特定的某一次,如果这种情况不满足条件,那么以这种情况为基础而生成的情况就不用再判断了,他们都不会满足条件。

比如说:头两行有冲突,那么后面的不管怎么放,都没有意义了,总会有冲突。

如下图:

《N皇后问题递归与非递归解法》

这时候我们就可以清楚看到,如果采用穷举法则问题规模是Q(n!),然后对这些可能情况,去掉对角线的情况.(因为行冲突,列冲突已经排除了).

但是如果我们放一个皇后判断一次,则有些情况就不必继续往下判断.

《N皇后问题递归与非递归解法》

从上图就可清晰地看明白,递归就是一个多叉树的深度优先遍历.

结果如下:(采用了两种方案,递归和非递归的回溯法)

《N皇后问题递归与非递归解法》

代码如下:

#include<stdio.h>
#include<math.h>

#define N     4
#define true  1
#define false 0
#define INITIAL  -1
typedef int bool;

int queen[N];
int count_recursive = 0;

void init_queen()
{
    int i;
    for(i = 0; i < N; i++)
    {
        queen[i] = INITIAL;
    }
}


void print_queen()
{
    int i, j;
    for(i = 0; i < N; i++)
    {

        for(j = 0; j < N; j++)
        {
            if(queen[i] == j)
                printf(" * ");
            else
                printf(" 0 ");
        }
        printf("\n");
    }

    printf("\n\n");
}

void place_queen(int row, int col)
{
    queen[row] = col;
}

bool valid(int row, int col)
{
    int i;
    for(i = 0; i < row; i++)
    {
        // in the same column
        if(queen[i] == col)
            return false;

        // in the same diagonal
        if(abs(row - i) == abs(col - queen[i]))
            return false;
    }
    return true;
}

int find_queen()
{
    int count = 0;
    int row = 0;
    int col = 0;
    while(row < N)
    {
        while(col < N)
        {


            if(valid(row, col))
            {
                place_queen(row, col);
                if(row == N-1)
                {
                    count ++;
                    printf("the %dst queen.\n", count);
                    print_queen();
                    col = queen[row];
                    col++;
                    queen[row] = INITIAL;
                }
                else
                {
                    col = 0; //goto tne next row
                    break;
                }
            }
            else
            {
                col ++;
            }
        }

        if(col == N)
        {
            // backtrace
            row--;
            if(row < 0) // find all the solutions
                return 0;
            else
            {
                col = queen[row];
                col++;
                queen[row] = INITIAL;
                continue;
            }
        }

        row++;
    }
}

int find_queen_recursive(int row, int col)
{
    int i;
    if(row > col)
    {
        count_recursive++;
        printf("the %dst queen.\n", count_recursive);
        print_queen();
    }
    else
    {
    for(i = 0; i < N; i++)
    {
        if(valid(row, i))
        {
            place_queen(row, i);
            find_queen_recursive(row + 1, col);
        }
    }
    }
}

int main()
{
    printf("not-recursive method:\n");
    init_queen();
    find_queen();

    printf("recursive method:\n");
    init_queen();
    find_queen_recursive(0, N - 1);
    return 0;
}

参考资料:http://www.cnblogs.com/yanlingyin/archive/2011/12/19/2292041.html

    原文作者:八皇后问题
    原文地址: https://blog.csdn.net/ustcjackylau/article/details/39670861
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞