回溯法之例~素数环

素数环—回溯法

问题介绍

给定数字 n ,排列从 1 到 n 的数字成环,使得相邻的俩数字之和为素数(质数)

问题分析

本文引入此问题是为了讲解下回溯法。介绍下回溯法:

大家应该知道迷宫,在走迷宫的时候选定一条道路,走不通回来继续走,走不通回来继续走… 回溯法类似,回溯嘛,就是走不对回来换条路呗,直到找到合适的问题解决方案。

再到本问题来,分析下数据结构,环嘛,就是线性的,所以用个一维数组存放环即可,在此定义环数组为 home,大小为 n 。对于一个环,要有一个起点,但是起点是哪个数字无所谓,在此初始化数组第一个元素
为 1 。另外需要另一个数组保存给定的数字的集合,所以定义该数组为 arr ,大小
为 n。上面讲到,已经初始化化环的第一个元素,所以就从该元素开始。逻辑部分如下:

取得环的当前最后一个元素 lastNumber,遍历数组 arr ,若遍历过程中当前数字
不存在于 home 数组中 且 当前数字与 lastNumber 和为质数,则将该数字添加
到环的末尾,准确说是指定下标的位置。到环的长度等于 n 时,便是一种解决方案。

代码实例(C语言)

#include<stdio.h>
#include<stdlib.h>
#include<Math.h>
int n = 16;					// 示例数值					
int arr[16];				// 用于存放所有的数值 
int home[16];				// 用于存放环 
int total = 0;				// 方法计数器 

void initArr(){				// 填充 arr[] 
	for (int i = 0; i < n; i++)
	{
		arr[i] = i + 1;
	}
}
void output(){				// 输出 home[] 
	for (int i = 0; i < n; i++)
	{
		printf("%d  ", home[i]);
	}
	printf("\n");
}
/*  判断当前数字是否存在于 home数组中    */
/*
	@param    number    被检测的数字
	@param    index     当前环的长度,也是环当前需放置数字的下标 
*/
bool isExist(int number, int index){	
	for (int i = 0; i < index; i++)
	{
		if (number == home[i]) return true;
	}
	return false;
}
/*  判断数字是否为质数 ( 需引入 #include<Math.h> )    */
/* @param  number   所检测数字  */
bool isPrime(int number){
	int sqrtNumber = sqrt(number);
	for (int i = 2; i <= sqrtNumber; i++)
	{
		if (number % i == 0) return false;	
	}
	return true;
}
/* 逻辑主函数(递归) */
/* @param  inedx  环当前需要放置元素的下标 */ 
bool prime(int index){
	/*  
		@条件判定   if    当前下标等于 n 并且当前环的第一个数字和最后一个数字和为素数( 环嘛 ) 
						{
						
							输出当前的环,方案+1 
						
						}
		@条件判定   else  
						{
							获取当前环的最后一个数字;
							遍历数组 arr
							若遍历中 该数字不存在于 home数组中 并且 与环中最后一个数字和为素数
							将该数字添加到环中,下标是指定的,切记,不是 push操作
							查找下一个 
							 
						}	
						
							
					 
		 
	*/
	if (index == n && isPrime(home[0] + home[index - 1])){
		output();
		total ++;
	}else {
		int lastNumber = home[index - 1];
		for (int i = 0; i < n; i++)
		{
			if (!isExist(arr[i], index) && isPrime(lastNumber + arr[i]))
			{
				home[index] = arr[i];
				prime(index + 1);
			}
		}
	}
}
int main(){
	initArr();				//初始 arr 
	home[0] = 1;			// 默认环第一个元素为 0 
	prime(1);				// 开始逻辑主函数 传入 下标 1 
	printf("方法:%d", total);
}

代码分析

其他不多说,分析下逻辑主函数 bool prime()。逻辑都在注释中,但是一定要注意添加新元素到环中,一定是指定的下标。这个也是回溯法的关键。

总结

回溯法其实是有模板的,而且非常结构非常典型,基本上可以按照模板解决相应的问题。回溯法最重要的地方就是试探当前状态 未来的所有情况,对于未来的某个情况也适用,如此递归下去,在递归开头设置满足递归结束的条件即可,唯一需要记住的是对于当前情况的保存一定是固定下标这样的。

    原文作者:回溯法
    原文地址: https://blog.csdn.net/I_m_Groot/article/details/83386818
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞