N皇后问题的一般解法--回溯法

先上代码

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
using namespace std;

vector<int> board;

void ShowQueen(void)
{
	for(unsigned int i = 0; i < board.size(); i++)
	{
		cout << "(" << i << "," << board[i] << ")  ";
	}
	cout << endl;
}

bool isValid(int rows, int cols, int order)
{
	if(rows >= order || cols >= order)
		return false;
	for(int i = 0; i < rows; i++)
	{
		if(cols == board[i])
			return false;
		else if(abs(cols-board[i]) == abs(rows-i))
			return false;
	}
	return true;
}

int QueenMutex(int k)
{
	if(k <= 3)
		return 0;
	int solutions = 0;
	board[0] = 0;
	int row = 1;
	int col = 0;
	while(row != -1)
	{
		if(isValid(row, col, k))
		{
			board[row] = col;
			if(row == k-1)
			{
				solutions++;
				ShowQueen();
				row--;
				col = board[row]+1;
			}
			else
			{
				row++;
				col = 0;
			}
		}
		else
		{
			col++;
			if(col >= k)
			{
				row--;
				col = board[row]+1;
			}
		}
	}
	return solutions;
}

int main(int argc, char const *argv[])
{
	int order = 4;
	if(argc == 2)
	{
		order = atoi(argv[1]);
		if(order <= 0)
		{
			order = 4;
		}
	}
	board.assign(order, 0);
	int n = QueenMutex(order);
	cout << "solutions: " << n << endl;
	
	return 0;
}

可以由参数指定要解决问题的规模N,我在ubuntu14.04 64bitOS下模拟出来,一共有92个解,时间10ms左右。


问题需求描述:在一个N×N的二维棋盘内,每行放置一个皇后,使得他们不能相互攻击。

转化:由皇后的走法规则直接将问题直接转化为任意两个皇后不能在同一行或同一列或任意45°角斜线上。


思考的问题1:棋盘和皇后的位置怎么表示?

        之前一直想的是用一个N*N的二维数组表示,毕竟这样比较直观。后来发现这样不仅浪费空间,而且也会浪费时间。

        一种比较好的办法是:用一个1×N的1维数组表,第i行的元素的值表示该行皇后所在的位置,行与行之间自然分开。

        全局容器board用来存放皇后的位置。

思考的问题2:思路

        利用穷举法和回溯法,将每一种可能的组合都尝试一边,符合要求的就输出,否则回到上一行皇后的下一个位置开始继续尝试。因此只要写出判断一个皇后的位置是否合法,即可比较清晰地理解思路。该函数为bool isValid(int rows, int cols, int order);若该皇后符合要求,将其位置放到相应的board元素中board[row] = col; 并判断皇后是否已经全部放置好,若是则输出,进而再回到上一行尝试其他组合(line45---50),若不是,则将row加1,进入下一行的判断。若该皇后不符合要求, 将列数加1,继续判断。同时要判断是否到达边界,若是则返回上一行继续尝试(line61---64)。这就是所谓的回溯。本题中由于要找到所有的解,所以不管是找到满足要求的解,还是发现当前组合不能满足时,都要进行回溯。如果只要求找到一种解,则对前一种情况返回即可,而后一种情况仍需回溯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章