算法-N皇后问题

2018/9/23

N皇后问题:在NxN的棋盘上,放置N个棋子, 使得同一行、同一列、同一对角线上只有一个棋子,问有多少种满足条件的放置方法?

 

参考:1.https://blog.csdn.net/hackbuteer1/article/details/6657109 N皇后问题的两个最高效的算法 

        回溯法和位运算法

方法1: 【回溯法】 回溯法也叫试探法,她是一种系统地搜索问题的解的方法。

               回溯法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。

    回溯法是解决一种问题的“万能算法”,这种问题是:需要将所有可能情况都穷举出来,然后从中找出满足某种要求的可能情况或最优解,从而得到整个问题的解。

/******

* 非递归方法的一个重要问题时何时回溯及如何回溯的问题。

程序首先对N行中的每一行进行探测,寻找该行中可以放置皇后的位置,具体方法是对该行的每一列进行探测,看是否可以放置皇后,

如果可以,则在该列放置一个皇后,然后继续探测下一行的皇后位置。如果已经探测完所有的列都没有找到可以放置皇后的列,

此时就应该回溯,把上一行皇后的位置往后移一列,如果上一行皇后移动后也找不到位置,则继续回溯直至某一行找到皇后的位置或回溯到第一行,

如果第一行皇后也无法找到可以放置皇后的位置,则说明已经找到所有的解程序终止。

如果该行已经是最后一行,则探测完该行后,如果找到放置皇后的位置,则说明找到一个结果,打印出来。

但是此时并不能再此处结束程序,因为我们要找的是所有N皇后问题所有的解,此时应该清除该行的皇后,从当前放置皇后列数的下一列继续探测。

*

*回溯法解N皇后问题

*使用一个一维数组表示皇后位置a[N]

*其中数组的下标表示皇后所在的行row, 数组元素值表示皇后所在的列

*这样设计的棋盘,所有皇后必定不在同一行,所以行冲突是不存在的

*********/

 

#include

#include

#include   //判断同一对角线上是否有冲突

 

using namespace std;

 

#define N      8   //皇后的数目

#define INIT   -100 //棋盘的初始值(尽可能小的负数),因为a[i]取值从0~N-1

 

int a[N];  //用一维数组表示棋盘

 

void queue_init()

{

    for (int i = 0; i < N; i++)

    {

        a[i] = INIT;

    }

}

 

bool judge_queue_valid(int row, int col)

{

    for (int i = 0; i < N; i++)

    {

        if (a[i] == col || abs(row - i) == abs(col - a[i])) //如果列冲突或者对角线冲突,则无效

        {

            return false;

        }

    }

    return true;

}

 

int queue_core()

{

    int i = 0, j = 0; //i表示row行号,j表示col列号

    int n = 0; //可行的放置方案数

 

    while (i < N)

    {

        while (j < N) //对i行中的每一列进行探测,看是否可以放置皇后

        {

            if (judge_queue_valid(i, j)) //判断放置此处是否满足N皇后条件

            {

                a[i] = j;  //满足条件在i行j列放置皇后

                j = 0;   //因为下一行又要从第一列开始遍历判断,所以列清零

                break;  //退出内循环

            }

            else //i行j列这个位置不满足N皇后条件

            {

                j++; //继续在此行下一列探测,直到此行最后一个位置探测完自然退出内循环

            }

        }

        //i行的所有N列已经探测完了,此处判断是否找到了满足条件的位置

        if (INIT == a[i]) //如果此行没有满足条件的,则需要回溯,回溯是从后往前依次重新判断

        {

            if (0 == i) //i==0,回溯到最后依次:说明刚刚的内循环是在第一行中寻找满足条件的解,但是可惜没有找到

            {

                break; //找完了所有满足条件的解,退出大循环

            }

            else  //不是最开始的一行,则往上回溯

            {

                i--;           //回溯到上一行

                j = a[i] + 1;  //从上一次满足条件的下一个位置resume judge

                a[i] = INIT;    //把上一行皇后的位置清除,重新探测

                continue;      // 设置好j后,重新开始内循环

            }

        }

 

        //如果a[i]不是初始值,则说明i行a[i]列满足条件,则继续往下执行

        if ( N - 1 == i) //i探测的结果是最后一行

        {

            n++; //满足的方案数目

            j = a[i] + 1;  //从最后一行放置皇后的下一列进行回溯探测

            a[i] = INIT;  //清除最后一行的皇后位置

            continue;

        }

 

        i++; //如果第i行满足条件,并且不是最后一行,则继续探测下一行

 

    }//end while(i

 

    return n;

}

 

 

int main()

{

    int solution_count = 0;

    queue_init();

    solution_count = queue_core();

 

    cout << solution_count << endl;

    system("pause");

    return 0;

}

 

 

 

方法1: 【位运算法】  --未完待续。。。

         位运算基本操作的意义:

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(数据结构和算法)