关闭

回溯算法之 N皇后问题

673人阅读 评论(0) 收藏 举报
// n皇后
#include <stdio.h>
#include <string.h>

#define MAX 15

int n;    //n queen
int cur;  //cur row
int A[MAX];    //the ith row's queen put in the A[i]th column
int tot = 0;    // total nums


//cur 为当前遍历到的行。
//从第1~n列中选择一列,使当前皇后放到此位置时,与已经放好的1~cur-1行的皇后不冲突(即不在同一行、同一列、两个对角线上)
void search(int cur)
{
	int i, j;
	if (cur==n+1)        //找到n个皇后的位置,打印出
	{
		for (i=1; i<cur; i++)
			printf("%d ", A[i]);
		printf("\n");
		tot++;
		return;
	}
	for(i=1; i<=n; i++)       //遍历1~n列找到其中的一列可以用来放置当前的皇后
	{
		int ok = 1;
		A[cur] = i;
		for (j=1; j<cur; j++)       //判断是否与之前已经放置的1~cur-1行的皇后有冲突
			if (A[cur] == A[j] || cur-A[cur] == j-A[j] || cur+A[cur] == j+A[j])    //在同一列/两个对角线上
			{   ok = 0;  break;   }

		if (ok)      //找到继续需找下一个皇后
			search(cur+1);
	}
}


int main()
{
	while (scanf("%d", &n)!=EOF)
	{
		memset(A, 0, sizeof(A));
		tot = 0;

		search(1);
		printf("%d\n", tot);
	}
	return 0;
}



注意到上面程序中判断第i列是否能放当前cur行的皇后的效率比较低,可以改进。

用一个全局变量vis[2][ ] 来保存某列、某主对角线、某副对角线已经被皇后占用。

这样就可以直接判断第i行是否可以放当前的皇后了。

void search2(int cur)
{
	int i, j;
	if (cur == n+1)
	{
		for (i=1; i<cur; ++i)
			printf ("%d ", A[i]);
		printf ("\n");
		tot++;
		return ;
	}


	for (i=1; i<=n; ++i)
	{
		if (!vis[0][i] && !vis[1][i+cur] && !vis[2][cur-i+n])      //判断是否可以放置当前皇后(效率比前面的高)
		{
			A[cur] = i;
			vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 1;     //修改全局变量的值使当前皇后放置位置的列、两条对角线被占用
			search2(cur+1);
			vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 0;     //回溯,一定要将前面修改过的值改回来!
		}
	}
}


第一次写这个程序时将循环计数变量i,j误设置为全局变量,导致程序运行结果不正确。这是一个递归程序,i,j应该为局部变量,才不会导致进一步递归时程序破坏上一次递归栈的局部数据!!



参考文献:《算法竞赛入门经典》 刘汝佳 编著


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:316981次
    • 积分:3256
    • 等级:
    • 排名:第10851名
    • 原创:73篇
    • 转载:0篇
    • 译文:6篇
    • 评论:89条
    公告
    最新评论
    友情链接