ACM_素數環
阿新 • • 發佈:2018-04-13
編寫 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; 8return 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_素數環