N皇后问题(递归、非递归回溯法;位运算求解N皇后)

目录

N皇后问题

数据范围

分析

C++代码(递归回溯法)

非递归回溯法

C++代码(非递归回溯法)

使用位运算求解N皇后问题

位运算求解N皇后代码


N皇后问题

n−皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后之间不能相互攻击到彼此,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

N皇后问题(递归、非递归回溯法;位运算求解N皇后)_第1张图片

现在给定整数 n,请你输出所有的满足条件的棋子摆法,以及一共有多少种能够满足条件的棋子摆法。

数据范围

1<=n<=20

分析

B站上关于N皇后问题的求解视频:

C++代码(递归回溯法)

#include

using namespace std;

#define Max 20  //定义棋盘的最大值 
#define MaxCount 1000  //定义最大的结果个数 

int N;

int direction_x[8] = {0, 1, 1, 1, 0, -1, -1, -1}, direction_y[8] = {1, 1, 0, -1, -1, -1, 0, 1};  //控制8个方向 
 
char queen[Max][Max];  //皇后位置棋盘 
int attack[Max][Max];  //皇后可攻击状态棋盘 

char solve[MaxCount][Max][Max];  //存储N皇后问题的全部解法
int solve_count = 0;  //solve数组的第一维 

/* 定义函数put_queen(),实现在(x,y)处放置皇后,对attack数组进行更新 */
void update_attack(int attack[][Max], int x, int y) 
{
	attack[x][y] = 1; //先将皇后所在位置(x,y)处置为1,表示不可再放置皇后 
	int nx,ny;
	//通过两层循环,将该皇后可能攻击到的位置进行标记 
	for(int l=1; l=0 && nx=0 && ny>N;  //皇后个数为N
	 
	//初始化棋盘和皇后可攻击状态棋盘(*代表皇后所在棋盘位置、o代表普通棋盘位置;0表示不可被攻击,1表示可以被攻击) 
	for(int i=0; i

非递归回溯法

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

C++代码(非递归回溯法)

#include
#include
#include

using namespace std;

#define Max 20      //定义棋盘的最大值

int a[Max];

int show(int S)    //定义输出函数
{
	int i,p,q;
  	int b[Max][Max]={0};     //定义并初始化b[][]输出数组
  	for(i=1; i<=S; i++)    //按横列i顺序输出a[i]数组坐标
  	{
		b[i][a[i]] = 1;
        printf("(%d,%d)\t",i,a[i]);
  	}
  	printf("\n");
  	for(p=1;p<=S;p++)     //按棋盘的横列p顺序标明皇后的位置
  	{
		for(q=1;q<=S;q++)
        {
            if(b[p][q]==1)     //在第p行第q列放置一个皇后棋子
                printf("●");
            else
                printf("○");
        }
        printf("\n");
  	}
  	return 0;
}
 
int check(int k)    //定义check函数
{
  	int i;
  	for(i=1; i 0)
  	{
    	if(k<=num && a[k]<=num)//从第k行第一列的位置开始,为后续棋子选择合适位子
        {
            if(check(k) == 0)    //第k行的a[k]列不能放置皇后
            {
                a[k]++;        //继续探测当前行的下一列:a[k]+1
            }
            else
            {
                k++;        //第K行的位置已经确定了,继续寻找第k+1行皇后的位置
                a[k] = 1;      //从第一列开始查找
            }
        }
        else
        {
            if(k>num)     //若满足输出数组的要求则输出该数组
            {
                count++;
                printf("[%d]:  ",count);
                show(num);    //调用输出函数show()
            }
            //如果k>num会执行下面两行代码,因为虽然找到了N皇后问题的一个解,但是要找的是所有解,需要回溯,从当前放置皇后的下一列继续探测
            //如果a[k]>num也会执行下面两行代码,就是说在当前行没有找到可以放置皇后的位置,于是回溯,从上一行皇后位置的下一列继续探测
            k--;      //棋子位置不符合要求,则退回前一步
            a[k]++;   //继续试探下一列位置
        }
  	}
  	printf("The count is: %d \n",count);
}
 
int main()
{
  	clock_t start,finish;
  	int n;
  	printf("请输入皇后个数:");
  	scanf("%d",&n);
  	start = clock();
  	printf("\n使用非递归回溯法解决 %d 皇后问题时的运行情况:\n",n); 
  	check_m(n);
  	finish = clock();
  	printf("计算时间 %.2f ms\n", (double) (finish - start));
  	system("pause");
  	return 0;
}

使用位运算求解N皇后问题

N皇后问题(递归、非递归回溯法;位运算求解N皇后)_第2张图片

N皇后问题(递归、非递归回溯法;位运算求解N皇后)_第3张图片

N皇后问题(递归、非递归回溯法;位运算求解N皇后)_第4张图片

位运算求解N皇后代码

#include
#include

using namespace std;

//方案链表
list sol;

//棋盘大小
int n;

//棋盘摆满时的数字
int uplimit;

void print()
{
	cout<::iterator i;
	for(i = sol.begin(); i != sol.end(); i++)
	{
		int temp = *i, count = 0;
		while(temp != 1)
		{
			count++;
			temp = temp >> 1;
		}
		for(int j = 0; j < count; j++)
			cout<<"o"<<" ";
		cout<<"*"<<" ";
		for(int j = count+1; j < n; j++)
			cout<<"o"<<" ";
		cout<>1);  //(ld+p)<<1和(rd+p)>>1是将对角线下移
			 
			//答案出
			sol.pop_back(); 
		} 
	}
	else
		print();
}

int main()
{
	while(cin>>n)
	{
		//如果n为8,则uplimit为11111111,表示每一行都有皇后了
		uplimit = (1 << n) - 1;
		doAns(0, 0, 0); 
	}
	return 0;
}

 

 

 


 

你可能感兴趣的:(刷题库,c++,算法,数据结构)