八皇后问题(回溯法)

//n皇后问题效率更高的解法
#include <iostream>
using namespace std;
void search(int step);
const int maxn=100;
int n,ans=0;
int a[maxn];
int vis[3][maxn];//“3”表示3种问题,vis[0][]表示"是否同列",vis[1][]表示"是否同主对角线",vis[2][]表示"是否同副对角线"
int main()
{
	cin>>n;
	search(0);
	cout<<ans<<endl;
	return 0;
}

void search(int step)//step可看作是 行
{
	int i,j;
	if (step==n) 
	{
		ans++;
		for (i=0;i<n;i++)
			cout<<a[i];
		cout<<endl;
	}
	else for (i=0;i<n;i++)//遍历 列
	{
		if (!vis[0][i] && !vis[1][step+i] && !vis[2][step-i+n])//判断 列(i),主对角线(step+i),副对角线(step-i+n) 是否已经有皇后了
		{
			a[step]=i;//把该 列数 放入数组a中以便打印各种情况的解
			vis[0][i]=vis[1][step+i]=vis[2][step-i+n]=1;//标记当前位置为1,说明已经有皇后
			search(step+1);//递归到下一个皇后
			vis[0][i]=vis[1][step+i]=vis[2][step-i+n]=0;//恢复为“未放”状态
			//如果在回溯法中使用了辅助的全局变量,则一定要即时把它们恢复原状。特别地,若函数有多个出口,则需在每个出口处回复被修改的值
		}
	}
}


/*回溯法:在某种情况下,递归函数将不再递归调用它自身,而是返回上一层调用,这种现象成为回溯(backtracking)。 
  递归枚举算法常被成为回溯法*/  
//要满足"八皇后",实际上就是恰好每行每列放置一个皇后.  
//如果用a[step]表示"第step行"皇后的"列编号"(即皇后的坐标为(step,a[step])),则问题变成了全排列生成问题  
#include <iostream>  
using namespace std;  
void search(int);  
const int maxn=10;  
int n,ans=0;//n表示要求n皇后的问题("八"皇后问题的话,n就是8);ans用来计数有多少种解法  
int a[maxn];//数组a用来表示“列”  
int main()  
{  
    cin>>n;  
    search(0);  
    cout<<ans<<endl;  
    return 0;  
}  
  
void search(int step)  
{  
    int i,j;  
    if (step==n) ans++;//递归边界:只要走到这里,说明所有皇后都必然不冲突  
    else for (i=0;i<n;i++)  
    {  
        int ok=1;   //ok是标记变量,用来判断该皇后是否与前面所放置的皇后有冲突,1代表无冲突,0代表有冲突  
        a[step]=i;  //尝试把第step行(个)的皇后放在第i列  
        for (j=0;j<step;j++) //判断第step行(个)的皇后所放的位置是否与前面的皇后有冲突  
            if (a[step]==a[j] || step-a[step]==j-a[j] || step+a[step]==j+a[j])   
            {  
                ok=0;  
                break;  
            }//一旦发现皇后有冲突,ok=0,并马上退出判断循环,并选择其他列  
            //***"a[step]==a[j]"用来判断是否同列  
            //***"step-a[step]==j-a[j]"和"step+a[step]==j+a[j]"用来判断是否在同一对角线  
        if (ok) search(step+1);//如果ok=1,即第step行(个)皇后放置成功,然后就继续递归求第step+1行(个)皇后位置  
    }  
} 


N皇后问题解的个数
1       1 
2       0 
3       0
4       2
5       10
6       4 
7       40 
8       92 
9       352 
10      724 
11      2680 
12      14200 
13      73712 
14      365596 
15      2279184 
16      14772512 
17      95815104 
18      666090624 
19      4968057848 
20      39029188884 
21      314666222712 
22      2691008701644 
23      24233937684440 
24      227514171973736 
25      2207893435808352 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值