回溯法之N皇后问题(四皇后)

回溯法(英语:backtracking)是暴力搜寻法中的一种。
回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。

n皇后问题:
就是nxn的国际象棋棋盘上,逐行放置皇后,要求每一行,每一列,每一条斜线都只能放置一个皇后。

回溯过程分析:
1.从空棋盘起,逐行放置棋子
2.每在一个布局中放下一个棋子,即推演到一个新的布局
3.如果当前行上没有可合法放置棋子的位置,则回溯当上一行,重新布放上一行的棋子。

以四皇后为例,给出回溯的求解过程图:
在这里插入图片描述
数据结构分析:
1.二位数组A[N][N]存储皇后位置,若第i行第j列有皇后,则A[N][N]为非0值,否则值为0.
2.一位数组M[k]、L[k]、R[k]分别表示竖列、左斜线、右斜线是否放有皇后,有则值为1,否则值为0.

j列上放置皇后时,M[j]=1,否则为0;
在这里插入图片描述
左斜线上,i+j的值一致,一共7条斜线(2N-1),对应L数组中的7个位置,比如说A[2][3]=1,也就是说第2行3列放置皇后,则L[i+j]=L[5]=1,表示第5+1=6条左斜线有一个皇后。
在这里插入图片描述
右斜线上,i-j的值一致,由于会出现负值,所以i-j+N,处理成正值,一共7条斜线(2
N-1),对应R数组中的7个位置,比如说A[2][3]=1,也就是说第2行3列放置皇后,则L[i-j+N]=L[-1+4]=L[3]=1,表示第3条右斜线有一个皇后。
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
#define N 100
int a[N][N]={0};//用来保存象棋布局,a[i][j]为0表示没有放置皇后,为非0值表示放置皇后
int M[N]={0};//M[j]=0表示第j列没有皇后,=1表示第j列已经放置了皇后
int L[N]={0};//L[j]=0表示第j条左斜线上没有皇后,=1表示第j条左斜线已经放置了皇后
int R[N]={0};//R[j]=0表示第j条右斜线上没有皇后,=1表示第j条右斜线已经放置了皇后
int n;//n皇后问题,n x n棋盘
int num;
int count;

void print()
{
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			printf("%d ",a[i][j]);
		}
		printf("\n");
	}
}

int solve(int i)
{
	for(int j=0;j<n;j++)
	{
		if(!M[j] && !L[i+j] && !R[i-j+n])//检查某一列,某一斜线上只有一个皇后
		{
			a[i][j]=i+1;
            M[j]=L[i+j]=R[i-j+n]=1;
            if(i==n-1)//逐行放置皇后,当放到最后一行的时候输出
            {
            	printf("\n");
            	print();
            	count++;
            }
            else
            {
            	solve(i+1);
            }
            a[i][j]=0;//去除皇后,回退
            M[j]=L[i+j]=R[i-j+n]=0;
		}
	}
	return count;
}
int main()
{
	scanf("%d",&n);
	num=solve(0);
	printf("%d\n",num);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值