c/c++求解N皇后问题(递归,栈,暴力)

问题分析考虑八皇后问题,最简单的方法就是对棋盘的每个格子进行有或没有的判断。得到的问题规模就是O(2^(n*n)),也就是2的64次方。指数增长的时间复杂度是非常可怕的,不推荐这种做法,但是考虑不同人对问题的思考,下面将会摆出暴力解N皇后的解法。下面给出的各种解法都采用了空间换时间的方式,设置一个数组a,数组下标表示的哪一行,数组的值表示的是哪一列。
(1)暴力解:对n = 8的问题来说,皇后所在的行为0 ~ 7。因此,8个皇后可能存储位置在00000000~77777777共8^8种情况。基于暴力分析的时候,该问题可以看作是8的8进制数字。基于该思想的代码如下。

#include<stdio.h>
#include<math.h>
#define n 8
int place(int a[n])
{
	int i, j;
	for(i = 0; i < n; i++)
		for (j = i + 1; j < n; j++)
		{
			if ((a[i] == a[j]) || (abs(a[i] - a[j]) == abs(i - j)))//不同列和斜线
				return 0;
		}
	return 1;
}
int main()
{
	int a[n];
	int num, temp;
	int i;
	int count = 0;

	for (num = 0; num < pow(n, n); num++)
	{
		temp = num;
		for (i = 0; i < n; i++)
		{
			//八进制
			a[i] = temp%n;
			temp = temp / n;
		}
			if (place(a))
			{
				count++;
				for (i = 0; i < n; i++)
				{
					printf("(%d,%d) ", i+1,a[i]+1);
				}
				putchar('\n');
			}
		
	}
	printf("total is : %d\n", count);
	return 0;
}

(2)递归解:递归的本质是栈,因此第三个方法就是栈。对于递归来说,同样有数组a,作用同上。递归的过程就是函数本身调用本身的过程。在八皇后中,这种递归叫做直接递归;还有一种递归方式是间接递归。递归是一种思考方式,并没有迭代的方式好。以下给出递归的代码。

#include <stdio.h>
#include <math.h>
/*N皇后问题*/
#define N 8

int a[N] = { 0 };
int count = 2;

int space(int row)
{
	int j;
	for (j = 0; j < row; j++)
	{
		if ((a[row] == a[j]) || (abs(a[row] - a[j]) == abs(row - j)))//不同列和斜线
			return 0;
	}
	return 1;
}

void dfs(int row)// row一行一个
{
	int k;
	if (row == N)
	{
		count += 1;
		for ( k = 0; k < N; k++)
			printf("(%d,%d)", k + 1, a[k] + 1);
		printf("\n");
	}

	int i;
	for( i = 0; i < N; i++)
	{
		a[row] = i; //列数推移
		if (space(row))
			dfs(row + 1);
	}
}

int main()
{
	dfs(0);
	printf("总共 %d 个\n", count -2 );
	return 0;
}

(3)栈解:对于学过数据结构的人来说,栈并不陌生,它也是一种线性结构,不过它是受限制的,坚持先进后出的原则。你可以把它想像成一个装水的竹筒,只能从一边装水,然后从同一边倒水。下面给出的代码。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MaxSize 100
typedef struct
{
	int data[MaxSize];//data[i]存放第i个皇后的列号
	int top;			
} StType;				
int count = 0;
int place(StType st, int i, int j)//测试(i,j)是否与1~i-1皇后有冲突
{
	int k = 1;
	while (k <= i - 1)//j=1到k-1是已放置了皇后的列
	{
		if ((st.data[k] == j) || (fabs(j - st.data[k]) == fabs(i - k)))
		{
			return 0;
		}
		else
			k++;
	}
	return 1;
}
void queen(int n)					
{
	int i, j, k;
	int find = 0;
	StType st;						
	st.top = 0;	//top=0时栈为空					
	st.top++;//将(1,1)进栈
	st.data[st.top] = 1;
	while (st.top>0)//栈不空时循环
	{
		i = st.top;//当前皇后为第i个皇后
		if (st.top == n)			
		{
			printf("第%d个解:", ++count);
			for (k = 1; k <= st.top; k++)
				printf("(%d,%d) ", k, st.data[k]);
			printf("\n");
		}
		find = 0;//每次退栈时重新检查是否能放
		for (j = 1; j <= n; j++)
			if (place(st, i + 1, j))//在i+1行找到一个放皇后的位置(i+1,j)
			{
				st.top++;
				st.data[st.top] = j;
				find = 1;
				break;
			}
		if (find == 0)//找不到放皇后的位置,回溯
		{
			while (st.top>0)
			{
				if (st.data[st.top] == n)//本列没有可放位置,退栈
					st.top--;
				for (j = st.data[st.top] + 1; j <= n; j++)//在本列找下一个位置
					if (place(st, st.top, j))
					{
						st.data[st.top] = j;
						break;
					}
				if (j>n)//当前皇后在本列没有可放的位置
					st.top--;
				else//本列找到一个位置后退出回溯
					break;
			}
		}
	}
}

int main()
{
	int n;
	printf(" 皇后问题(n<20) n=");
	scanf("%d", &n);
	printf(" %d皇后问题求解如下:\n", n);
	queen(n);
	printf("\n");
	return 0;

}
  • 2
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值