1. 程式人生 > >素數環問題---回溯

素數環問題---回溯

size pre argv 。。 color cstring ++ ons 結果

素數環

題目:輸入正整數n,把整數1。2,3,...,n組成一個環。使得相鄰兩個整數之和均為素數。

輸出時從整數1開始逆時針排列。

同一個環應該恰好輸出一次。n<=16

分析:首先運用普通方法(生成測試法)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int maxn =1e3;
 8 int isp[maxn];
9 int A[maxn]; 10 int n; 11 int ans=0; 12 13 int is_prime(int x){ 14 for( int i=2; i*i<=x; i++ ){ 15 if(x%i==0) return 0; 16 } 17 return 1; 18 } 19 20 int main(){ 21 cin>>n; 22 for( int i=2; i<=n*2; i++ ) isp[i]=is_prime(i);/*生成素數表,加快後續判斷*/ 23 for
( int i=0; i<n; i++ ) A[i]=i+1; 24 do{ 25 int flag=1; 26 for(int i=0; i<n; i++ ){ 27 if(!isp[A[i]+A[(i+1)%n]]){/*不是素數,這種排列方式行不通*/ 28 flag=0; 29 break; 30 } 31 } 32 if(flag){ 33 ans++; 34
for( int i=0; i<n; i++ ) cout<<A[i]<<" "; 35 cout<<endl; 36 } 37 }while(next_permutation(A+1,A+n));/*第一個位置是1!*/ 38 cout<<ans<<endl; 39 return 0; 40 }

這種方法當n=12就已經很慢了,n=16無法輸出結果。。。

思路二:回溯法。。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 const int maxn =1000;
 7 int vis[maxn];
 8 int A[maxn];
 9 int isp[maxn];
10 int n;
11 int ans=0;
12 
13 int is_prime(int x){
14     for( int i=2; i*i<=x; i++ ){
15         if(x%i==0) return 0;
16     }
17     return 1;
18 }
19 
20 void dfs(int cur){
21     if(cur==n&&isp[A[0]+A[n-1]]){
22         ans++;
23         for( int i=0; i<n; i++ ) cout<<A[i]<<" ";
24         cout<<endl;
25     }
26     else{
27         for(int i=2; i<=n; i++ ){
28             if(!vis[i]&&isp[i+A[cur-1]]){/*i這個數沒被用過,並且符合前後兩個數相加為素數的要求*/
29                 A[cur]=i;/*采用這個數*/
30                 vis[i]=1;/*設置使用標誌*/
31                 dfs(cur+1);
32                 vis[i]=0;/*消除標誌*//*回溯的本質*/
33             }
34         }
35     }
36 }
37 int main(int argc, char const *argv[])
38 {
39     cin>>n;
40     memset(vis,0,sizeof(vis));
41     for( int i=2; i<=n*2; i++ ) isp[i]=is_prime(i);
42     A[0]=1;/*題目中規定從1開始*/
43     dfs(1);
44     cout<<ans<<endl;
45 
46     return 0;
47 }

素數環問題---回溯