#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
const int Max = 40;
bool prime[Max];
bool vis[Max];
int A[Max];
int n;
void IsPrime() {
prime[0] = prime[1] = 0; prime[2] = 1;
for(int i = 3; i < Max; i++)
prime[i] = (i%2 == 0) ? 0 : 1;
int t = (int)sqrt(Max*10);
for(int i = 3; i <= t; i++)
if(prime[i])
for(int j = i*i; j < Max; j += 2*i)
prime[j] = 0;
}
void dfs(int cur) {
if(cur == n && prime[A[0]+A[n-1]]) {
for(int i = 0; i < n; i++) //打印的时候是从A[0]开始打印的
{printf("%d", A[i]);if(i != n-1) printf(" ");}
printf("\n");
}
else for(int i = 2; i <= n; i++)
if(!vis[i] && prime[i+A[cur-1]]) {
// 如果这个数还没有使用过并且和前一个数之和为素数的话
A[cur] = i;
vis[i] = 1;
dfs(cur+1);
vis[i] = 0; //清除标志
}
}
int main(){
int cnt = 0;
IsPrime();
while(scanf("%d", &n) != EOF) {
memset(vis, 0, sizeof(vis));
printf("Case %d:\n", ++cnt);
A[0] = 1;
dfs(1);
printf("\n");
}
return 0;
}
更新时间:2016/3/17;
重写了一遍:
理清思路: 首先确定好所有的素数,然后看递归过程:只能以1开头, 那就先存起来, 然后将“当前选什么”(从2开始)作为状态, 判断条件是当前这个数和上一个数要形成素数。最后的边界是和第一个数1相加然后判断。
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
using namespace std;
const int maxn = 20*2;
int no_prime[maxn], vis[maxn];
int cas, N;
map<int , int> M;
void pre() { //这个筛法的写法还是不太记得啊。。印象不够深刻
no_prime[0] = no_prime[1] = 1;
memset(no_prime, 0, sizeof(no_prime));
int m = sqrt(maxn+0.5); //sqrt的参数类型是double ,返回值类型也是double, 加0.5以四舍五入, 防止精度缺损导致少了个数
for(int i = 2; i <= m; i++) if(!no_prime[i])
for(int j = i*i; j <= maxn; j+=i) //这里边界一定要注意,别写错!!
no_prime[j] = 1;
}
void Print() {
for(int i = 1; i <= N; i++)
printf(i!=1?" %d":"%d", M[i]);
printf("\n");
}
void dfs(int cur) {
if(cur > N+1) return ;
if(cur > N && !no_prime[M[N]+M[1]]) {
Print();
return ;
}
for(int i = 1; i <= N; i++)
if(!vis[i] && !no_prime[i+M[cur-1]]) {
vis[i] = 1; M[cur] = i;
dfs(cur+1);
vis[i] = 0; M[cur] = 0;
}
return ;
}
int main() {
pre();
cas = 0;
while( scanf("%d", &N)!= EOF) {
memset(vis, 0, sizeof(vis));
M.clear();
printf("Case %d:\n", ++cas);
vis[1] = 1;
M[1] = 1;
dfs(2);
printf("\n");
}
return 0;
}