一、題目描述:
把整數{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)。