素数环问题

一、题目描述:
把整数{1,2,3,…,20}填到一个环中,要求每个整数只填写一次,并且相邻的两个整数之和是一个素数。例如,下图所示就是{1,2,3,4}对应的一个素数环。

二、解题思路:

​ 这个素数环有20个位置,每个位置可以填写一次,并且相邻为1~20,共20种可能,可以对每个位置从1开始进行试探,约束条件是正在试探的数满足如下条件:

​ (1)与已经填写到素数环中的整数不重复;

​ (2)与前面相邻的整数之和是一个素数;

​ (3)最后一个填写到素数环中的整数与第一个填写的整数之和是一个素数。

​ 在填写第k个位置时,如果满足上述约束条件,则继续填写第k+1个位置;如果1~20都无法填写到第k个位置,则取消第k个位置的填写,回溯到第k-1个位置。

三、伪代码:

四、流程图:

五、源程序:

#include<iostream>
#include<math.h>
using namespace std;

bool isPrime(int x)	//判断整数x是否是素数 
{
	int n = (int)sqrt(x);
	for(int i=2; i<=n; i++)
		if(x%i == 0) return false;
	return true;
}

bool isLegal(int k, int n, int a[])	//判断位置k填写是否满足约束条件 
{
	for(int i=0; i<k; i++)		//判断即将填写的值是否与填写过的重复 
		if(a[i] == a[k]) return false;
	if(!isPrime(a[k]+a[k-1])) return false;	//判断相邻数之和是否为素数
	if(k==n-1 && !isPrime(a[k]+a[0])) return false;	//判断第一个和最后一个之和是否为素数 
	return true;
}

void primeCircle(int n)
{
	int a[n];	//用数组a[]来存储素数环 
	for(int i=0; i<n; i++)	//将数组所有元素都初始化为0 
		a[i] = 0;
	
	a[0] = 1;
	int k = 1;
	while(k>=1)
	{
		a[k] = a[k]+1;
		while(a[k]<=n)
		{
			if(isLegal(k,n,a)) break;	//位置k可以填写整数a[k]
			else a[k] = a[k]+1;	//试探下一个数 
		}
		
		if(a[k]<=n && k==n-1)	//求解完毕,输出素数环 
		{
			for(int i=0; i<n; i++)
				cout<<a[i]<<" ";
			cout<<endl;
			return;
		}
		
		if(a[k]<=n && k<n-1) k++;	//填写下一个
		else a[k--] = 0;	//回溯 
	}
}

int main()
{
	primeCircle(20);
	return 0;
}

六、算法分析:

1、空间复杂度分析

​ 空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。针对本题目所设计的程序在运行过程中,需要存储素数环的空间和其它的一些临时变量,临时变量可忽略,所以,只需要考虑一个大小为n的数组。由此分析出,本算法的空间复杂度为O(n)。

2、时间复杂度分析

​ 时间复杂度是同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。在计算机科学中,算法的时间复杂度是一个函数,它定性描述了该算法的运行时间。对于本题目,设要填写1~n共n个整数,由于每个位置可以填写的情况有n种,因此,素数环问题的解空间数是一棵完全n叉树,且树的深度为n+1,由此可分析出,最坏情况下的时间性能为O(n^n)。

原文地址:https://www.cnblogs.com/godfriend/p/10981894.html