回溯算法之 N皇后问题

// 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值