回溯算法-八皇后问题

在这里插入图片描述
在我们的一生中,会遇到很多重要的岔路口。在岔路口上,每个选择都会影响我们今后的人生。有的人在每个岔路口都能做出最正确的选择,最后生活、事业都达到了一个很高的高度;而有的人一路选错,最后碌碌无为。如果人生可以量化,那如何才能在岔路口做出最正确的选择,让自己的人生“最优”呢?

2004 年上映了一部非常著名的电影《蝴蝶效应》,讲的就是主人公为了达到自己的目标,一直通过回溯的方法,回到童年,在关键的岔路口,重新做选择。当然,这只是科幻电影,我们的人生是无法倒退的,但是这其中蕴含的思想其实就是回溯算法。

1. 什么是“回溯算法”?

回溯法(back tracking)(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

白话:回溯法可以理解为通过选择不同的岔路口寻找目的地,一个岔路口一个岔路口的去尝试找到目的地。如果走错了路,继续返回来找到岔路口的另一条路,直到找到目的地。

理论的东西还是过于抽象,我还是举例说明一下。我举一个经典的回溯例子,我想你可能已经猜到了,那就是八皇后问题。

2. 八皇后问题

八皇后问题是一个古来而著名的问题,该问题是19世纪著名的数学家高斯同学提出来的。在8*8的国际象棋上摆放八个皇后,使其不能互相的攻击,也就是说,任意的两个皇后不能放在同一行或则是同一个列或者是同一个对角线上,问有多少个摆放的方法

你可以看下图,第一幅图是满足条件的一种方法,第二幅图是不满足条件的。八皇后问题就是期望找到所有满足这种要求的放棋子方式。
在这里插入图片描述
我们把这个问题划分成 8 个阶段,依次将 8 个棋子放到第一行、第二行、第三行……第八行。在放置的过程中,我们不停地检查当前的方法,是否满足要求。如果满足,则跳到下一行继续放置棋子;如果不满足,那就再换一种方法,继续尝试。

回溯算法非常适合用递归代码实现,所以,我把八皇后的算法翻译成代码。我在代码里添加了详细的注释,你可以对比着看下。如果你之前没有接触过八皇后问题,建议你自己用熟悉的编程语言实现一遍,这对你理解回溯思想非常有帮助。

bool is_ok(int row, int column)
{
	int leftup = column - 1, rightup = column + 1;
	for (int i = row-1; i >= 0; --i) { // 逐行往上考察每一行
		if (result[i] == column) return false; // 第 i 行的 column 列有棋子吗?
		if (leftup >= 0) { // 考察左上对角线:第 i 行 leftup 列有棋子吗?
			if (result[i] == leftup) return false;
		}
		if (rightup < 8) { // 考察右上对角线:第 i 行 rightup 列有棋子吗?
			if (result[i] == rightup) return false;
		}
		--leftup; ++rightup;
	}

	return true;
}

void print_queen(int result[])
{
    for(int row = 0; row < 8; ++row){
        for(int col = 0; col < 8; ++col){
            if(result[row]==col){
                printf("Q ");
            }else{
                printf("* ");
            }
        }
        printf("\n");
    }
}

void cal8queen(int row)
{
	if(8 == row){
		print_queen(result);
		return;
	}
	for(int col = 0; col < 8; ++col){
		if(is_ok(row,col)){
			result[row] = col;
			cal8queen(row+1);
		}
	}
}

代码链接:https://github.com/cvtuge/Algorithm/tree/master/8queen

3. 最后

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值