八皇后问题 EightQueen

题目:在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;
}


你可能感兴趣的:(递归,八皇后)