C++“八皇后问题”之回溯法

程序分析:在8*8的棋盘上安置八个皇后且相互不能攻击。

一个皇后的攻击范围如下图所示:
在这里插入图片描述
其中一种摆法如下:在这里插入图片描述
C++代码:

方法一:

#include <iostream>
using namespace std;

const int ArSize = 8;//这个数等于几,就是几皇后。
int num = 0;

bool check(bool arr[ArSize][ArSize], int row, int column){
	// 判断皇后的落点是否合规
	if (row == 0){
		return true;
	}
	int i, j;
	
	for (i = 0; i < row; ++i){
		// 判断纵向是否有冲突
		if (arr[i][column]){
			return false;
		}
    }

	i = row - 1;
	j = column - 1;
	while (i >= 0 && j >= 0){
		// 判断正斜对角线是否有冲突
		if (arr[i][j]){
			return false;
		}
		--i;
		--j;
	}

	i = row - 1;
	j = column + 1;
	while (i >= 0 && j <= ArSize - 1){
		// 判断负斜对角线是否有冲突
		if (arr[i][j]){
			return false;
		}
		--i;
		++j;
	}
	return true;
}

void outPut(bool arr[ArSize][ArSize]){
	// 打印每种正确的解法
	++num;
	cout << "**********************" << num << "*********************" << endl;
	for (int i = 0; i < ArSize; ++i){
		for (int j = 0; j < ArSize; ++j){
			cout << arr[i][j] << " ";
		}
		cout << endl;
	}
	cout << "*********************************************" << endl;
}

void solve(bool arr[ArSize][ArSize], int row) {
	// 回溯法
	for (int column = 0; column < ArSize; ++column) {
		arr[row][column] = true;
		if (check(arr, row, column)) {
			if (row + 1 == ArSize) {
				outPut(arr);
			}
			else {
				solve(arr, row + 1);
			}
		}
		arr[row][column] = false;
	}
}

int main()
{
	bool chessboard[ArSize][ArSize];
	// 数组初始化
	for (auto &i : chessboard){
		for (auto &j : i){
			j = false;
		}
	}
	/*
	//数组初始化方法二
	for (int i = 0; i < ArSize; i++) {
		for (int j = 0; j < ArSize; j++) {
			chessboard[i][j] = false;
		}
	}
	*/
	solve(chessboard, 0);
	cout << "八皇后问题共有" << num << "种解!" << endl;
	system("pause");
	return 0;
}

方法二:

#include<iostream>
#include<vector>//用向量保存皇后
using namespace std;

class Queen {
public:
	short x;
	short y;
	Queen(short _x, short _y) :x(_x), y(_y) {}
	bool Attack(Queen &queen) {
		//能相互攻击返回true
		return x == queen.x || x - y == queen.x - queen.y || x + y == queen.x + queen.y || y == queen.y;
	}
};

void PrintQueens(vector<Queen> &v,int *count) {
	cout << "第" << *count << "种摆法:" << endl;
	short i, j;
	vector<Queen>::iterator itr1 = v.begin();
	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++) {
			if (itr1 != v.end()&&i == itr1->y&&j == itr1->x) {
				cout << "后";
				itr1++;
			}
			else {
				cout << "□";
			}
			
		}
		cout << endl;
	}
	(*count)++;
}

int main() {
	vector<Queen> vt;
	short i, j;
	vector<Queen>::iterator itr;//迭代器
	Queen *q;
	int count=1;
	for (i = 0; i < 8; i++) {
		j = 0;
Repeat:
		for (; j < 8; j++) {
			q = new Queen(j, i);
			for (itr = vt.begin(); itr != vt.end(); itr++) {
				if (q->Attack(*itr)) {
					//新皇后与原来的皇后进行攻击测试
					delete q;
					break;
				}
			}
			if (itr == vt.end()) {
				//新皇后与原来皇后不冲突
				vt.push_back(*q);
				delete q;
				if (vt.size() == 8) {
					PrintQueens(vt, &count);//输出八皇后解法
					j = 8;//人为赋值,使流程进入 if(j==8)回溯重试
				}
				break;//退出列遍历,直接到下一行的第一列
			}
		}
		if (j == 8) {
			//当前的一整行都无法安放皇后
			if (vt.back().x == 7) {
				//向量尾部的皇后若刚好是当前行最后一列的位置,不能将x后移,必须多弹出一次
				vt.pop_back();//弹出
			}
			if (!vt.empty()) {
				i = vt.back().y;
				j = vt.back().x + 1;
				vt.pop_back();
				goto Repeat;
			}
		}
	}
	return 0;
}

C++运行结果:

方法一:
在这里插入图片描述方法二:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值