n皇后问题

问题描述:

在n*n格的棋盘上放置n个皇后,其中任意的2个皇后不在同一行或同一列或是同一斜线上,即任意2个皇后不在一条直线上。

 

解法一递归回溯法:

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

typedef int BOOL;
#define TRUE 1
#define FALSE 0
#define N 20

void place(int x2);
void print_result();
void backtrack(int line);
void recursive_queen(int n);

static int n;			// 棋盘的规模,也是皇后的个数
static int sum = 0;		// n皇后问题解的个数
static int s[N];		// n元组s表示n皇后问题的解,s[i]表示皇后i放在棋盘的第i行的第s[i]列

int main() {
	
	printf("输入n值: ");
	scanf ("%d", &n);
	if (n <= 0 && n > N) {
		printf("n ERROR!\n");
		exit(EXIT_FAILURE);
	}

	recursive_queen(n);
	printf("%d\n", sum);

	return EXIT_SUCCESS;
}

/*
** 递归回溯法求解n皇后问题
*/
void recursive_queen(int n) {
	int i;

	for (i = 0; i < n; i++)
		s[i] = 0;

	backtrack(0);			// 从第0行开始摆放皇后
	printf("共有%d摆放法。\n", sum);
}

/*
** 递归回溯法求解
** line表示当前正要摆放皇后的行数
*/
void backtrack(int line) {
	int i;

	if (line >= n){						// 已经摆放完每一行,得出解
		sum++;
		print_result();
	} else {							// 还未摆放完
		for (i = 0; i < n; i++) {			// 从第0列开始到第n-1列,逐一地去尝试摆放
			s[line] = i;
			if (place(line))				// 如果可以摆放,则摆放下一行;否则尝试下一列
				backtrack(line+1);
		}
	}
}

/*
** 两个皇后不能在同一列上,即s中的任意两个不同的s[i], s[j]互不相同;
** 两个皇后不能在同一斜线上,即任意两个皇后连成的直线斜率不为±1,
** 即对点(x1, y1)和(x2, y2),|x1 - x2| != |y1 - y2|
*/
BOOL place(int x2) {
	int x1;
	for (x1 = 0; x1 < x2; x1++){
		if ( (s[x1] == s[x2]) || (abs(x1 - x2) == abs(s[x1] - s[x2])) ) {
			return FALSE;
		}
	}
	return TRUE;
}

/*
** 打印皇后摆放位置的结果
*/
void print_result() {
	int i, j;

	printf("第%d种摆放法:\n", sum);
	for (i = 0; i < n; i++ ) {
		for (j = 0; j < n; j++) {
			if (j == s[i])
				printf("■");		// 放置皇后
			else
				printf("□");		// 未放置皇后
		}
		putchar('\n');
	}
	putchar('\n');
}


解法二迭代回溯法:

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

typedef int BOOL;
#define TRUE 1
#define FALSE 0
#define N 20

BOOL place(int x2);
void print_result();
void iterative_queen(int n);

static int n;			// 棋盘的规模,也是皇后的个数
static int sum = 0;		// n皇后问题解的个数
static int s[N];		// n元组s表示n皇后问题的解,s[i]表示皇后i放在棋盘的第i行的第s[i]列

int main() {
	
	printf("输入n值: ");
	scanf ("%d", &n);
	if (n <= 0 && n > N) {
		printf("n ERROR!\n");
		exit(EXIT_FAILURE);
	}

	iterative_queen(n);
	printf("%d\n", sum);

	return EXIT_SUCCESS;
}

/*
** 迭代回溯法求解n皇后问题
*/
void iterative_queen(int n) {
	int line = 0;			// 当前正要摆放皇后的行数
	
	s[0] = 0;				// 第0列从第0行开始迭代		

	while (line >= 0) {		// 当回溯至第-1行时,迭代结束
		
		while ( (s[line] < n) && !place(line) )		// 寻找下一个可以放置皇后的列
			s[line]++;

		if (s[line] < n) {							// 存在可以放置皇后的列
			if (line == n - 1) {					// 求得问题解
				sum++;
				print_result();
			} else {								// 还未求得问题解
				line++;								// 迭代下一行
				s[line] = 0;						// 下一行从第0列开始迭代
				continue;
			}
		} else										// 每一列都不能够放置皇后,回溯
			line--;

		s[line]++;									// 迭代下一列
	}
}


/*
** 两个皇后不能在同一列上,即s中的任意两个不同的s[i], s[j]互不相同;
** 两个皇后不能在同一斜线上,即任意两个皇后连成的直线斜率不为±1,
** 即对点(x1, y1)和(x2, y2),|x1 - x2| != |y1 - y2|
*/
BOOL place(int x2) {
	int x1;
	for (x1 = 0; x1 < x2; x1++){
		if ( (s[x1] == s[x2]) || (abs(x1 - x2) == abs(s[x1] - s[x2])) ) {
			return FALSE;
		}
	}
	return TRUE;
}

/*
** 打印皇后摆放位置的结果
*/
void print_result() {
	int i, j;

	printf("第%d种摆放法:\n", sum);
	for (i = 0; i < n; i++ ) {
		for (j = 0; j < n; j++) {
			if (j == s[i])
				printf("■");		// 放置皇后
			else
				printf("□");		// 未放置皇后
		}
		putchar('\n');
	}
	putchar('\n');
}

 

结果输出:

输入n值: 6
第1种摆放法:
□■□□□□
□□□■□□
□□□□□■
■□□□□□
□□■□□□
□□□□■□

第2种摆放法:
□□■□□□
□□□□□■
□■□□□□
□□□□■□
■□□□□□
□□□■□□

第3种摆放法:
□□□■□□
■□□□□□
□□□□■□
□■□□□□
□□□□□■
□□■□□□

第4种摆放法:
□□□□■□
□□■□□□
■□□□□□
□□□□□■
□□□■□□
□■□□□□

共有4摆放法。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值