直接枚举n!个效率不高,回溯法更优
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int Max = 10000; bool isp[Max]; int vis[Max]; int a[Max]= {1}; int n; void is_prime(int n) { memset(isp,true,sizeof(isp)); isp[0] = isp[1] = false; for(int i = 2; i <= 2*n; i++) if(isp[i] == true) //打点到2n的位置 { for(int j = i*2; j <= 2*n; j += i) isp[j] = false; } } void dfs(int cur) { if(cur == n && isp[a[0] + a[n-1]]) { for(int i = 0; i < n; i++) printf("%d",a[i]); printf("\n"); return; } for(int i = 2; i <= n; i++) if(!vis[i] && isp[i+a[cur-1]]) { a[cur] = i; vis[i] = 1; dfs(cur+1); vis[i] = 0; } } int main() { scanf("%d",&n); is_prime(n); dfs(1); return 0; }
优化素数环
#include <iostream> #include <cstring> using namespace std; const int Max = 40; int visit[Max]; int a[Max]; int prime[Max]; int sign = 0; int cnt = 0; void prim() { //数据是0~20,素数和最大18+19,不超过40,素数打表 for(int i = 0; i <= Max;i++) prime[i] = 1; prime[0] = prime[1] = 0; for(int i = 2; i * i < Max; i++) if(prime[i] == 1) for(int j = i + i; j <= Max; j = j+i) prime[j] = 0; } void dfs(int x,int n,int step) { if(step == n&&prime[a[step-1]+a[0]]) { sign = 1; for(int i = 0; i < n; i++) cout << a[i] << ' '; cout << endl; return; } for(int i = 2; i <= n;i++) if(/*prime[i]&&&*/prime[x+i]&&!visit[i]&&(x+i)%2==1)//剪枝,和前一个数的和不是素数的剪去 { a[step] = i; visit[i]= 1; dfs(i,n,step+1); visit[i] = 0; } } int main() { int n; while(cin >> n) { sign = 0; if(n == 0) return 0; cout << "Case " << ++cnt << ":" << endl; if(n==1) //坑 {cout << 1 << endl; continue; } if(n%2==1) { //奇数个数其中必有两个奇数相加为大于2的偶数,该偶数必定不是素数,无法组成素数环 cout << "No Answer" << endl; continue;
} memset(visit,0,sizeof(visit)); a[0] = 1; prim(); //打表 dfs(1,n,1); if(sign == 0) cout << "No Answer" << endl; } return 0; }