回溯---n后递归和非递归方法

       把棋盘存储为一个N维数组a[N],数组中第i个元素的值代表第i行的皇后位置,这样便可以把问题的空间规模压缩为一维O(N)。

        在判断是否冲突时也很简单,首先每行只有一个皇后,且在数组中只占据一个元素的位置,行冲突就不存在了,其次是列冲突,判断一下是否有a[i]与当前要放置皇后的列j相等即可。至于斜线冲突,通过观察可以发现所有在斜线上冲突的皇后的位置都有规律即它们所在的行列互减的绝对值相等,即| row –  i | = | col – a[i] | 。这样某个位置是否可以放置皇后的问题已经解决。

       但是一般来说递归的效率比较差,下面重点讨论一下该问题的非递归实现。

       非递归方法的一个重要问题是何时回溯及如何回溯的问题。程序首先对N行中的每一行进行探测,寻找该行中可以放置皇后的位置,具体方法是对该行的每一列进行探测,看是否可以放置皇后,如果可以,则在该列放置一个皇后,然后继续探测下一行的皇后位置。如果已经探测完所有的列都没有找到可以放置皇后的列,此时就应该回溯,把上一行皇后的位置往后移一列,如果上一行皇后移动后也找不到位置,则继续回溯直至某一行找到皇后的位置或回溯到第一行,如果第一行皇后也无法找到可以放置皇后的位置,则说明已经找到所有的解,程序终止。如果该行已经是最后一行,则探测完该行后,如果找到放置皇后的位置,则说明找到一个结果,打印出来。但是此时并不能再此处结束程序,因为我们要找的是所有N皇后问题所有的解,此时应该清除该行的皇后,从当前放置皇后列数的下一列继续探测。

#include<iostream>
using namespace std;
int num = 0;

bool Place(int *ar,int k)
{
	for(int j = 1;j<k;++j)
	{
		if(ar[k] == ar[j] || abs(k-j) == abs(ar[k] - ar[j]))
		{
			return false;
		}
	}
	return true;
}

void PrintAr(int *ar,int n)
{
	for(int i = 1;i<=n;++i)
	{
		for(int j= 1;j<=n;++j)
		{
			if(ar[j] == i)
			{
				cout<<"@ ";
			}
			else
			{
				cout<<"# ";
			}
		}
		cout<<endl;
	}
	cout<<endl;
}


//   非递归
int main()
{
	const int n = 4;
	int ar[n+1]={0,0,0,0,0};
	int k = 1;
	ar[k] = 0;
	while(k >= 1)
	{
		ar[k]+=1;
		while(ar[k] <= n && !Place(ar,k)) ar[k]+=1;
		if(ar[k] <= n)
		{
			if(k >= n)
			{
				PrintAr(ar,n);
			}
			else
			{
				k+=1; 
				ar[k] = 0;
			}
		}
		else
		{
			--k;
		}
	}
	return 0;


/*
//递归
void nQueue(int *ar,int k,int n)
{
	if(k > n)
	{
		num+=1;
		PrintAr(ar,n);
	}
	else
	{
		for(int i = 1;i<=n;++i)
		{
			ar[k] = i;
			if(Place(ar,k))
			{
				nQueue(ar,k+1,n);
			}
		}
	}
}

int main()
{
	const int n = 8;
	int ar[n+1]={0,0,0,0,0};
	nQueue(ar,1,n);
	cout<<num<<endl;
	return 0;
}
*/

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值