1. 程式人生 > >ACM_素數環

ACM_素數環

編寫 tle font sin cin i++ ems c代碼 深搜

Problem Description:

如圖所示,環由n個圓組成。 將自然數1,2,...,n分別放入每個圓中,並且兩個相鄰圓中的數字總和應為素數。

註意:第一個圓圈的數量應該始終為1。

技術分享圖片

Input:

n (0 < n < 20). 

Output:

輸出格式如下所示。 每行代表從1開始順時針和逆時針旋轉的一系列圓圈數字。 數字的順序必須符合上述要求。 按照字典順序打印解決方案。

你要編寫一個完成上述過程的程序。

即使沒有答案,也會在每個案例後打印一個空行。

Sample Input:

6
8

Sample Output:

Case 1:
1 4 3 2 5 6
1 6 5 2 3 4

Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
解題思路:dfs。先打表記錄40以內是素數的數組isp,因為相鄰數之和有可能最大為39,所以只需枚舉到39。關於字典序輸出,這裏每枚舉到當前這個數,從2開始到n枚舉哪些數是滿足條件,有的話就將當前這個數記錄在path數組中,並且標記這個數已經被訪問,再遞歸下去尋找下一個數,如果遞歸不滿足條件的話,將當前這個數置為0。每當cur==n時就輸出當前素數環。其中有一個剪枝
的操作,如果給定的整數n為奇數,那麽肯定不存在素數環,(因為肯定存在兩個奇數相鄰,而奇數與奇數的和為偶數,所以一定不是素數環)這個節省了不少遞歸時間,不然老是TLE-_-||。
AC代碼:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,isp[40]={0},vis[20],path[20];//vis數組是保存標記,path是記錄
 4 int is_prime(int t)//判斷素數
 5 {
 6     for(int i=2;i*i<=t;++i)
 7         if(t%i==0)return 0;
 8
return 1; 9 } 10 void dfs(int cur) 11 { 12 if((cur==n) && isp[path[1]+path[n]]){//遞歸邊界 如果cur==n && isp(1+path[n])是素數,則終止條件 13 for(int i=1;i<n;i++) 14 cout<<path[i]<< ; 15 cout<<path[n]<<endl; 16 return ; 17 }
18 else{ 19 for(int i=2;i<=n;++i){//嘗試放置每個數i 20 if(!vis[i] && isp[i+path[cur]]){ //如果i沒用過 21 path[cur+1]=i;//且i加上與之相鄰的上一個數之和是素數,則把它賦給path[cur+1]; 22 vis[i]=1; //設置使用標誌 23 dfs(cur+1); //深搜 24 vis[i]=0; //清除標誌 25 } 26 } 27 } 28 } 29 int main() 30 { 31 for(int i=2;i<40;++i) //生成素數表,枚舉到最大的2倍即可 32 isp[i]=is_prime(i); 33 int k=1; //Case情況數 34 while(cin>>n){ 35 cout<<"Case "<<k++<<:<<endl; 36 memset(vis,0,sizeof(vis)); 37 vis[1]=1,path[1]=1;//將1作為path開頭,且標記已訪問 38 if(n>0 && (n%2==0))dfs(1);//剪枝,如果是偶數的話,必有素數環,從1開始深搜 39 cout<<endl; 40 } 41 return 0; 42 }
 

ACM_素數環