经典算法:dfs暴搜,剪枝| 8月更文挑战

671 阅读2分钟

这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战

想要坚持写点什么,那干脆写一个系列吧。想想有什么可以写的呢?程序=算法+数据结构,可见算法的重要性。这个系列老诗力求用最简单的语言把算法讲得明明白白,由浅到深,有兴趣的话,可以关注一下专栏。

上一篇文章介绍了基础的回溯法,剪枝。然后用全排列做了例子。接下来更加深入地去研究,这种算法应该怎么去深入。记得上一篇文章我还特意留下了作业让大家有兴趣的话一定要去做一做,因为挺经典的。

标题:五星填数

如图的五星图案节点填上数字:1~12,除去7和11。要求每条直线上数字和相等。

如图就是恰当的填法。

请你利用计算机搜索所有可能的填法有多少种。注意:旋转或镜像后相同的算同一种填法。

请提交表示方案数目的整数,不要填写任何其它内容。

image.png

这道题目需要去重,因为是五角星* 5(因为每个角是可以旋转的,所以这些都是可以认定是相同的),且镜像 * 2,所以暴搜之后直接/10就是去重之后的数量。

然后我们再把重点放在暴搜上面。

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
int a[11];      //五角星的数 
int n;          //记录成立个数
int isUse[110];   //记录这些数是否用过
void dfs(int s){
	if(s==11){
		int f = a[2] + a[3] + a[4] + a[5];
		int b  = a[1] + a[3] + a[6] + a[9];
		int c  = a[1] + a[4] + a[7] + a[10];
		int d  = a[2] + a[6] + a[8] + a[10];
		int e  = a[5] + a[7] + a[8] + a[9];
		if(f==b && b==c && c==d && d==e){
			n++;
			return ;
		}
		return ;
	}
	for(int i=1;i<=12;i++){
		if(i==7||i==11||isUse[i]){
			continue;
		}
		isUse[i] = 1;
		a[s] = i;
		dfs(s+1);
		isUse[i] = 0;
	}
	return ;
}
int main()
{
	dfs(1); 
	cout<<n/10; //5*2
	return 0;
}

总的来说整到题目如果知道算法的话并不是太难,也就是直接套入模板就行了。dfs中填入每一个数,也就是和全排列差不多,然后这里加上剪枝数字不能等于7和11,还是数字不能被用过。用isUse记录数字是否被用过。isUse[i] = 1;标记为用过dfs完了之后需要标记为isUse[i] = 0;也就是没用过,这就是回溯法的特色。

其实这种回溯可以用到很多地方,例如寻路算法,也就是在试一试哪个方向格子可以更好走而已。

更多的干货内容,项目源码,可以关注公众号:诗一样的代码

既然进来了,原创不易。小伙伴点个赞再走呗