素数环问题----回溯法应用(1)
问题描述:
把整数{1, 2, …, 20}填写到一个环中,要求每个整数只填写一次,并且相邻的两个整数之和是一个素数。
例如,{1, 2, 3, 4}的填写结果:
算法思想:
这个素数环有20个位置,每个位置可以填写的整数有1~20共20种可能,可以对每个位置从1开始进行试探,约束条件是正在试探的数满足如下条件:
(1)与已经填写到素数环中的整数不重复;
(2)与前面相邻的整数之和是一个素数;
(3)最后一个填写到素数环中的整数与第一个填写的整数之和是一个素数。
在填写第k个位置时,如果满足上述约束条件,则继续填写第k+1个位置;如果1~20个数都无法填写到第k个位置,则取消对第k个位置的填写,回溯到第k-1个位置。
伪代码:
void PrimeCircle(int n) //填写1~n共n个整数
{
int i,k;
for(i=0;i<n;i++)
a[i]=0;
a[0]=1; k=1;
while(k>1)
{
a[k]=a[k]+1;
while(a[n]<=n)
if(Check(k)==1) break;
else a[k]=a[k]+1;
if(a[k]<=n&& k==n-1)
{
for(i=0;i<n;i++)
cout<<a[i]<<" ";
return ;
}
if(a[k]<=n&& k<n-1)
{
k=k+1;
}
else a[k--]=0;
}
}
int Check(int k) //检查位置K的填写是否满足约束条件
{
int flag=0;
for(int i=0;i<k;i++)
if(a[i] == a[k]) return 0;
flag =Prime(a[k]+a[k-1]);
if(flag == 1 && k == n-1)
flag= Prime(a[k]+a[0]);
}
int Prime(int x) //判断是否是素数
{
int i,n;
n =(int)sqrt(x);
for(i=2;i<=n;i++)
if(x%i == 0) return 0;
return 0;
}