八皇后问题 EightQueen

来源:互联网 发布:淘宝助理大头笔设置 编辑:程序博客网 时间:2024/06/06 20:44

题目:在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即要求任意两个皇后不得处在同一行、同一列或者同一对角斜线上。求出总共有多少种摆法。

思路一:

    对于不在同行且不在同列的摆法,8行每行各有一个皇后,那么就是在8列中进行全排列,很明显有8!种情况。在这8!中情况中,再排除对角斜线上在出现冲突的情况。

    对于排列组合类型的问题,经常采用递归方式来解决。

数据结构:因为每行注定只能有1个皇后,因此我们采用一维数组,只保存皇后的所在的列号:int ColunmIndex[8]; 数组的序号代表皇后所在的行号,对应元素代表皇后所在的列号。

需要解决的问题有:

1、如何判断一个ColunmIndex是否满足不在对角斜线上冲突?

    观察发现,位于矩阵中同一斜线上的两个元素有这样的特点:行号的差和列号的差的绝对值一致。

    对于正斜线,行号的差=列号的差;对于反斜线,行号的差= -列号的差。

2、如何得到全排列组合各种情况的ColunmIndex?

    排列的生成是组合数学中的一个内容。这一数量级的问题经常使用递归。排列组合的各种情况可以通过两两交换的方式得到。首先我们可以把数组的第1个元素分别和每个元素两两交换,这样会得到8中排列形式(包括自己和自己交换的情况),这样每个数都有机会做1号元素了;这8种情况下分别在此基础之上(下面的问题看作8个递归子问题),再把第2个元素和其之后的每个元素(包括第2个元素自己)两两交换,各得到7种排列形式,8种情况下就有8*7种排列形式,这样每个数都有机会做2号元素了…………就是这样的依次的方法,得到了8!种不同的排列形式。

    这种产生全排列数据的递归方式是非常值得学习和复用的。

int data[N]={0,1,2,3,4,5,6,7,8};调用ProduceArray(data, 0);void ProduceArray(int data[], int index){int i;if(index < N){for(i=index;i<N;i++){swap(data[i], data[index]);ProduceArray(data, index+1);swap(data[i], data[index]);}}else{加入处理逻辑}}

完整代码:

#include <stdio.h>int num = 0;const int N = 8;int ColunmIndex[N];void printArray(int data[]){int i;num++;printf("No.%d : \n",num);for(i=0;i<N;i++)printf("%d  ",data[i]);printf("\n");}bool check(int data[]){int i,j;for(i=0;i<N;i++){for(j=i+1;j<N;j++){if( ((i-j)==(data[i]-data[j]))||((j-i)==(data[i]-data[j])))return false;}}return true;}void swap(int &a, int &b){int tmp = a;a = b;b = tmp;}void ProduceArray(int data[], int index){int i;if(index < N){for(i=index;i<N;i++){swap(data[i], data[index]);ProduceArray(data, index+1);swap(data[i], data[index]);}}else{if(check(data))printArray(data);}}void EightQueen(){int i;for(i=0;i<N;i++)ColunmIndex[i] = i;ProduceArray(ColunmIndex, 0);}int main(){EightQueen();return 1;}


思路二:由小到大逐渐扩大的递归。一行一行的扩展状态,每次扩展都既保证之前所有行都不冲突,又保证所有的情况都考虑进来。


代码:

#include <stdio.h>#include <stdlib.h>int num = 0;const int N = 8;int ColunmIndex[N];void printArray(int data[]){int i;num++;printf("No.%d : \n",num);for(i=0;i<N;i++)printf("%d  ",data[i]);printf("\n");}bool check(int row){    for(int i=0;i<row;i++)    {        int diff = abs(ColunmIndex[i]-ColunmIndex[row]);        if(diff == 0  || diff == row - i)            return false;    }    return true;}void placeQueen(int row){    if(row == N)    {        printArray(ColunmIndex);        return;    }        for(int i=0;i<N;i++)    {        ColunmIndex[row] = i;        if(check(row))            placeQueen(row+1);    }}int main(){    placeQueen(0);return 1;}


原创粉丝点击