n皇后问题回溯法详解

皇后放置的规则:不能同行,不能同列,也不能同对角线(正反双对角线)

先设置一下全局变量

#define N 8

int cnt=0;

char board[N][N];

N 为皇后个数

cnt 为一共有多少种放置方法

board 为棋盘,用于放置皇后和打印结果

主函数如下:

int main() {
	memset(board, '0', sizeof(board));

	dfs(0);
	printf("%d", cnt);
	return 0;
}

        用memset将board初始化

        dfs为算法函数,传入的参数 0 为当前已经放置了的皇后个数,并且在该函数内将要放置第 0+1 个皇后

dfs:

void dfs(int n) {	//表示已经放置了n个queen,第n+1个queen要放于何处
	//当放置的queen数量等于N
	if (n == N) {
		cnt++;
		display();
		printf("\n");
		return;
	}

	int i = n;
	for (int j = 0; j < N; j++) {
		//检查第i行第j列能否放入
		if (check(i, j)) {
			//能放入的话
			board[i][j] = '1';
			dfs(n+1);
			//放完之后回溯
			board[i][j] = '0';
		}
	}


}

        void dfs(int n){}        n 为当前已经放置的皇后个数,本次将要放置第 n+1 个皇后

当已经放置的皇后个数 n==N 时,证明找到了一种解,此时解的总数cnt++,同时使用display把当前解的棋盘布局打印出来方便观察。上述行为做完后return回溯

        int i=n        这里的 i 作为行号,因为每一行只能放置一个皇后(皇后不能同行),所以每当放置了一个皇后之后就跳过该行从下一行开始放置,由此也得出了第 n 个皇后将会被放置在第 n 行。因为每放置一个皇后我们都要检查行列和对角线,而通常我们习惯用 i 表示行用 j 表示列,所以这里用 i 作为行号

        有了行号之后还要设置列号,每当从新的一行放置皇后时都要从第 0 列开始遍历检查能否放置

        check(i,j)        检查第 i 行 第 j 列能否放置

        如果能够放入皇后,则把board中当前坐标的内容改为1

        dsf(n+1)        放入一个皇后之后开始放入下一个皇后

        board[i][j] = '0'        所有皇后都放完之后回溯,把改坐标的内容重新改为0,查找下一种解

接下来的关键就是如何check:

bool check(int i, int j) {
	//遍历board
	int x = 0; int y = 0;
	for (x = 0; x < i; x++) {
		for (y = 0; y < N; y++) {
			//当 任意一行的j列 或者 board[i][j]的正反对角线 已经有queen
			if ((y == j||x+y==i+j||x-y==i-j) && board[x][y] == '1') {
				return false;
			}
		}
	}
    return true;
}

        之前传入的坐标就是 i、j,这里用相同的临时变量接收

        新建 x、y用于遍历board,检查是否能在 board[i][j] 放置皇后

       

判断同行同列是否已有皇后:

        因为每次放完一个皇后之后,下一个皇后只能在下一行放,两个皇后在放之前就不可能放在同一行,所以这里只用判断同列。

        对 i 之前的每一行每一列进行遍历,当出现 board[x][y] == '1' && y == j 时,证明与 board[i][j] 同列已有皇后,return false;

判断同对角线(从左上往右下)是否已有皇后:

         对角线:

         我们现在想要在 [ i , j ] 放入皇后,可以发现与 [ i , j ] 同对角线的元素 [ x , y ] 的横纵坐标之差与 [ i , j ] 是一样的,这样当x-y==i-j && [ x , y ] 处已有皇后,return false

          反对角线:

         与 [ i , j ] 同对角线的元素 [ x , y ] 的横纵坐标之和与 [ i , j ] 是一样的,这样当x+y==i+j && [ x , y ] 处已有皇后,return false

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值