1008.素数环问题
时限:1000ms 内存限制:10000K 总时限:3000ms
描述
把1到20这重新排列,使得排列后的序列A满足:
a. 任意相邻两个数之和是素数
b. 不存在满足条件a的序列B使得:A和B的前k(0 <= k <= 19)项相同且B的第k+1项比A的第k+1项小。(即按字典序排列的第一项)
输入
没有输入。
输出
输出A,两个数字之间用一个空格隔开,第一个数字前面和最后一个数字后面没有空格。
输入样例
输出样例
提示
本题不提供输出样例。
解析:素数环是我第一次认真做这个题,刚开始的思路肯定是,第一个固定是1,从第二个开始,与第一个相加看是不是素数,如果是就直接进行下一个数的检验,如果不是就把第二个和后面几个依次相加直到找出一个素数为止。到第m个时,检验是否与a[m-1]个相加为素数,如是直接search(m+1)即可,如果不是将m与后面的每个数进行交换,如果找到就直接交换并且进行search(m+1),如果找不到就先换回来,即把m归位,(划重点!!)然后与剩下的交换,直到找到为止。最后的判断条件自然是m>20,而且还要a[1]+a[21]为素数才可以输出,不然就要返回上一层继续找。
此外,这个题目是回溯法找排列树,所以出现的模板是排列的模板,即有两个swap函数。回溯法可以生成两种树,排列树和子集树,二者是有差别的,我会在算法分类概述的回溯篇里中进行详细解释。
注:这里有个很坑的问题是我写完之后总是输出无穷个结果,最后查别人的代码才直到输出以后要加exit(0)表示结束进程,,,,希望各位注意。
代码如下:
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[21],cnt=0;
void init()
{
for(int i=0;i<21;i++)
a[i]=i;
}
int isprime(int num)
{
int i,k;
k=sqrt(num);
for(i=2;i<k;i++)
{
if(num%i==0)
return 0;
}
return 1;
}
void output()
{
for(int i=1;i<21;i++)
{
cout<<a[i]<<‘ ‘;
}
cout<<endl;
}
void search(int m)
{
if(m> 20)
{
if(!isprime(a[1]+a[20]))
return ;
else
{
output();
exit(0); //结束程序
}
}
else
{
for(int i=m;i<21;i++)
{
swap(a[m],a[i]);
if(isprime(a[m-1]+a[m]))
search(m+1);
swap(a[m],a[i]);
}
}
}
int main()
{
init();
search(2);
}