8皇后问题的递归解法(C++代码)

女神要考一下我最近学算法有没有进步,扔给我一个八皇后问题。
这个问题有多重要,怕是已经超越算法本身了,更像是个人形象大考。
于是花了一晚上加一上午的时间,用递归解了这个问题。
本文只讲算法本身,不讲程序中为博女神一笑的彩蛋部分,敲黑板,不讲彩蛋!

1.八皇后问题概述

来自女神发来的最原始的图: )D
在这里插入图片描述

2.递归算法思路

(1)因为每行能且只能放一个皇后,考虑递归的对每行进行处理
(2)设置一个全局的计数器,初始值为0
(3)八皇后问题有一些放置规则,因此维护一个状态矩阵,在这个矩阵中:值为1的地方代表已经放置了皇后,0代表空位,-1代表这个地方不能放皇后。状态矩阵的初始值全部为0
(4)在每一个递归体中,要遍历这一行的每一列,检查有没有空位,对每一个空位都要试探着放皇后
(5)如果在这一行找到一个空位,就在这个地方放一个皇后,然后更新因放这个皇后而导致的状态矩阵变化
(6)如果这一行有空位且已经放上皇后并更新过状态矩阵,那么递归地处理下一行,直到到达最后一行
(7)如果这一行已经没有空位,则return,这是试探不成功的情况,不对计数器做操作
(8)到达最后一行之后,数一数这一行一共有多少个空位,然后加到计数器上,把状态矩阵存盘

3. c++代码(已删除彩蛋)

#include<iostream>
#include<vector>
#include<time.h>
#include <Windows.h>

using namespace std;
static int count_num = 0;


bool put_quene_vector(vector<vector<int>> status, int row_index)//用vector传参速度很慢
{
	if (row_index == status.size() - 1)//若递归进入到最后一行
	{
		for (int j = 0; j < status.size(); j++)
		{
			if (status[row_index][j] == 0)
			{
				count_num++;
			}
		}
		return true;//如果递归结束,返回true
	}
	
	for (int j = 0; j < status.size(); j++)//遍历这一行
	{
		if (status[row_index][j] == 0)//这一行有空位
		{
			vector<vector<int>> status_copy(status);

			//试探性的在这个空位放皇后,并做好相应的更新操作
			for (int k = 0; k < status_copy.size(); k++)//更新东西南北方向的状态
			{
				status_copy[row_index][k] = -1;
				status_copy[k][j] = -1;
			}
			for (int m = row_index, n = j; m >= 0 && n >= 0 && m < status_copy.size() && n < status_copy.size(); m--, n--)//更新西北方向的状态
			{
				status_copy[m][n] = -1;
			}
			for (int m = row_index, n = j; m >= 0 && n >= 0 && m < status_copy.size() && n < status_copy.size(); m++, n--)//更新东北方向的状态
			{
				status_copy[m][n] = -1;
			}
			for (int m = row_index, n = j; m >= 0 && n >= 0 && m < status_copy.size() && n < status_copy.size(); m--, n++)//更新东南方向的状态
			{
				status_copy[m][n] = -1;
			}
			for (int m = row_index, n = j; m >= 0 && n >= 0 && m < status_copy.size() && n < status_copy.size(); m++, n++)//更新西南方向的状态
			{
				status_copy[m][n] = -1;
			}
			status_copy[row_index][j] = 1;//在这个空位上放皇后

			//递归地调用这个函数到下一行
			put_quene_vector(status_copy, row_index + 1);
		}
	}
	return true;
}



bool put_quene(int **status, int row_index, int compute_size)//用数组速度很快
{
	//if (A[7][8] == 0)cout << "00" << endl;
	//cout << "row_index:" << row_index << endl;

	if (row_index == compute_size - 1)//若递归进入到最后一行
	{
		for (int j = 0; j < compute_size; j++)
		{
			if (status[row_index][j] == 0)
			{
				count_num++;
			}
		}
		return true;//如果递归结束,返回true
	}

	for (int j = 0; j < compute_size; j++)//遍历这一行
	{
		if (status[row_index][j] == 0)//这一行有空位
		{
			//复制一下这个状态数组
			int **status_copy;
			status_copy = new int *[compute_size];
			for (int i = 0; i < compute_size; i++)
			{
				status_copy[i] = new int[compute_size];
				for (int j = 0; j < compute_size; j++)
				{
					status_copy[i][j] = status[i][j];
				}
			}

			//试探性的在这个空位放皇后,并做好相应的更新操作
			for (int k = 0; k < compute_size; k++)//更新东西南北方向的状态
			{
				status_copy[row_index][k] = -1;
				status_copy[k][j] = -1;
			}
			for (int m = row_index, n = j; m >= 0 && n >= 0 && m < compute_size && n < compute_size; m--, n--)//更新西北方向的状态
			{
				status_copy[m][n] = -1;
			}
			for (int m = row_index, n = j; m >= 0 && n >= 0 && m < compute_size && n < compute_size; m++, n--)//更新东北方向的状态
			{
				status_copy[m][n] = -1;
			}
			for (int m = row_index, n = j; m >= 0 && n >= 0 && m < compute_size && n < compute_size; m--, n++)//更新东南方向的状态
			{
				status_copy[m][n] = -1;
			}
			for (int m = row_index, n = j; m >= 0 && n >= 0 && m < compute_size && n < compute_size; m++, n++)//更新西南方向的状态
			{
				status_copy[m][n] = -1;
			}
			status_copy[row_index][j] = 1;

			//递归地调用这个函数到下一行
			put_quene(status_copy, row_index + 1, compute_size);
		}
	}
	return true;
}




void cal_mode()
{
	//动态二维数组的分配方法
	int **status;
	int compute_size;
	count_num = 0;
	cout << "小可爱输入一下计算规模吧 :)D" << endl;
	cin >> compute_size;
	status = new int *[compute_size];
	for (int i = 0; i < compute_size; i++)
	{
		status[i] = new int[compute_size];
		for (int j = 0; j < compute_size; j++)
		{
			status[i][j] = 0;
		}
	}
	cout << "男朋友CPU在全力运转中..." << endl;
	/*
	//用vector分配动态二维数组可能比较好,实验证明这个速度很慢
	int compute_size;
	cout << "小可爱输入一下计算规模吧 :)D" << endl;
	cin >> compute_size;
	vector<vector<int>> status(compute_size);
	for (int i = 0; i < status.size(); i++)
	status[i].resize(compute_size);
	*/

	DWORD start_time = GetTickCount();
	put_quene(status, 0, compute_size);
	DWORD end_time = GetTickCount();
	cout << "算出来啦!用时" << (end_time - start_time)<<"ms" << endl;
	Sleep(1*1000);
	cout << "难道就不输入I love you嘛.." << endl;
	char str[50];
	cin.getline(str, 50);
	cin.getline(str, 50);
	if (string(str) == string("I love you") || string(str) == string("I love u"))
		cout << "mua,这个问题一共有" << count_num << "种解法" << endl;
	else
	{
		cout << "啊,不是I love you哎..." << endl;
		Sleep(4 * 1000);
		cout << "emmm我想了想还是不能同意,重新输入" << endl;
		cin.getline(str, 50);
		while (string(str) != string("I love you") && string(str) != string("I love u"))
		{
			cout << "emmmm你说你爱我嘛" << endl;
			cin.getline(str, 50);
		}
		cout << "mua,I love u too! 这个问题一共有" << count_num << "种解法" << endl;
	}
}

void main()
{
	while (1)
			cal_mode();
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值