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