(蓝桥杯)从八皇后问题到2n皇后问题

引入:为了点击量丧心病狂地添加了蓝桥杯三个字,虽然并没有什么用

1. 八皇后问题

以国际象棋为背景:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。

使用回溯和递归的方法进行的求解

#include 
#include 
#include 
#include 
#include 

using namespace std;

int a[10][10];
// 摆在每行的哪一列
int thehang[10];
// 哪一列是否已有了
int ishas[10];
// 有多少组
int flag = 0;

void put(int hang, int lei)
{
	if (thehang[8] != 0)
	{
		for (int i = 1; i <= 8; i++)
		{
			printf_s("%d",thehang[i]);
		}
		cout << endl;
		flag++;
		return;
	}
	if (hang > 8 || lei > 8)
		return;

	// 第一行
	if (hang == 1)
	{
		a[hang][lei] = 1; ishas[lei] = 1; thehang[hang] = lei;
		// 从下一行第一列开始找
		put(hang + 1, 1);
		// 回溯,即返回到原来的样子
		a[hang][lei] = 0; ishas[lei] = 0; thehang[hang] = 0;
	}
	// 非第一行
	else {
		// 做下一行处理
		int temp;
		for (temp = 1; temp < hang; temp++)
		{
			// 是否同列有,对角线有(每行比)
			if (hang - temp == abs(thehang[temp] - lei) || thehang[temp] == lei)
			{
				put(hang, lei + 1);
				return;
			}
		}
		if(temp==hang)
		{
			a[hang][lei] = 1; ishas[lei] = 1; thehang[hang] = lei;
			put(hang + 1, 1);
			a[hang][lei] = 0; ishas[lei] = 0; thehang[hang] = 0;
		}
	}

	if (lei < 8)
		put(hang, lei + 1);
}

int main()
{
	memset(a, 0, sizeof(a));
	memset(ishas, 0, sizeof(ishas));
	put(1, 1);
	printf_s("%d", flag);
}

2. n皇后问题

棋盘的大小变为n×n,而皇后个数也变成n。(0

递归函数里增加一个参数表示n,用n来代替8,会了八皇后直接改参数就可以了
真是个小天才

#include 
#include 
#include 
#include 
#include 

using namespace std;

int a[10][10];
// 摆在每行的哪一列
int thehang[10];
// 哪一列是否已有了
int ishas[10];
// 有多少组
int flag = 0;

void put(int hang, int lei, int size)
{
	if (thehang[size] != 0)
	{
		for (int i = 1; i <= size; i++)
		{
			printf_s("%d",thehang[i]);
		}
		cout << endl;
		flag++;
		return;
	}
	if (hang > size || lei > size)
		return;

	// 第一行
	if (hang == 1)
	{
		a[hang][lei] = 1; ishas[lei] = 1; thehang[hang] = lei;
		// 从下一行第一列开始找
		put(hang + 1, 1, size);
		// 回溯,即返回到原来的样子
		a[hang][lei] = 0; ishas[lei] = 0; thehang[hang] = 0;
	}
	// 非第一行
	else {
		// 做下一行处理
		int temp;
		for (temp = 1; temp < hang; temp++)
		{
			// 是否同列有,对角线有(每行比)
			if (hang - temp == abs(thehang[temp] - lei) || thehang[temp] == lei)
			{
				put(hang, lei + 1, size);
				return;
			}
		}
		if(temp==hang)
		{
			a[hang][lei] = 1; ishas[lei] = 1; thehang[hang] = lei;
			put(hang + 1, 1, size);
			a[hang][lei] = 0; ishas[lei] = 0; thehang[hang] = 0;
		}
	}

	if (lei < size)
		put(hang, lei + 1, size);
}

int main()
{
	int n;
	cin >> n;
	memset(a, 0, sizeof(a));
	memset(ishas, 0, sizeof(ishas));
	put(1, 1, n);
	printf_s("%d", flag);
}

3. 2n皇后问题

问题来自于蓝桥杯

问题描述

给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。

输入格式

输入的第一行为一个整数n,表示棋盘的大小。
  接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
  输出一个整数,表示总共有多少种放法。

样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2
样例输入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
0

方法基本一致,细节以后再来解释
毕竟调试地要吐了

#include 
#include 
#include 
#include 
#include 

using namespace std;

int a[10][10];

// 白摆在每行的哪一列
int thehang[10];
// 白哪一列是否已有了
int ishas[10];

// 黑摆在每行的哪一列
int black_thehang[10];
// 黑哪一列是否已有了
int black_ishas[10];

// 有多少组
int flag = 0;

// 放黑皇后(0:不能放; 1:可以放; 2:放过白的了; 3:放过黑的了)
void put_black(int hang, int lei, int size)
{
	// 达成一次2n问题
	if (black_thehang[size] != 0)
	{
		flag++;
		return;
	}

	if (hang > size || lei > size)
		return;

	// 第一行
	if (hang == 1)
	{
		if (a[hang][lei] == 1)
		{
			a[hang][lei] = 3; black_ishas[lei] = 1; black_thehang[hang] = lei;
			// 从下一行第一列开始找
			put_black(hang + 1, 1, size);
			// 回溯,即返回到原来的样子
			a[hang][lei] = 1; black_ishas[lei] = 0; black_thehang[hang] = 0;
		}
	}
	// 非第一行
	else {
		// 做下一行处理
		int temp;
		for (temp = 1; temp < hang; temp++)
		{
			// 是否同列有,对角线有(每行比)
			if (hang - temp == abs(black_thehang[temp] - lei) || black_thehang[temp] == lei || a[hang][lei] != 1)
			{
				put_black(hang, lei + 1, size);
				return;
			}
		}
		if (temp == hang)
		{
			a[hang][lei] = 3; black_ishas[lei] = 1; black_thehang[hang] = lei;
			put_black(hang + 1, 1, size);
			a[hang][lei] = 1; black_ishas[lei] = 0; black_thehang[hang] = 0;
		}
	}

	if (lei < size)
		put_black(hang, lei + 1, size);
}

// 放白皇后(0:不能放; 1:可以放; 2:放过白的了)
void put(int hang, int lei, int size)
{
	if (thehang[size] != 0)
	{
		// 白的已经放好了
		put_black(1, 1, size);
		return;
	}
	if (hang > size || lei > size)
		return;

	// 第一行
	if (hang == 1)
	{
		if (a[hang][lei] == 1)
		{
			a[hang][lei] = 2; ishas[lei] = 1; thehang[hang] = lei;
			// 从下一行第一列开始找
			put(hang + 1, 1, size);
			// 回溯,即返回到原来的样子
			a[hang][lei] = 1; ishas[lei] = 0; thehang[hang] = 0;
		}
	}
	// 非第一行
	else {
		// 做下一行处理
		int temp;
		for (temp = 1; temp < hang; temp++)
		{
			// 是否同列有,对角线有(每行比)
			if (hang - temp == abs(thehang[temp] - lei) || thehang[temp] == lei || a[hang][lei] == 0)
			{
				put(hang, lei + 1, size);
				return;
			}
		}
		if(temp==hang)
		{
			a[hang][lei] = 2; ishas[lei] = 1; thehang[hang] = lei;
			put(hang + 1, 1, size);
			a[hang][lei] = 1; ishas[lei] = 0; thehang[hang] = 0;
		}
	}

	if (lei < size)
		put(hang, lei + 1, size);
}

int main()
{
	int n;
	cin >> n;
	memset(a, 0, sizeof(a));
	memset(ishas, 0, sizeof(ishas));
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
			scanf("%d", &a[i][j]);
	}
	put(1, 1, n);
	printf("%d", flag);
}

你可能感兴趣的:(算法)