1. 程式人生 > >回溯枚舉法

回溯枚舉法

void phi isf 位置 ant 圖片 blog 一個數 更多

回溯法也稱試探法,它可以系統的搜索一個問題的所有解或者任意解。

回溯法是一個既帶有系統性又帶有跳躍性的的搜索算法。它在包含問題的所有解的解空間樹中,按照深度優先的策略,從根結點

出發搜索解空間樹。算法搜索至解空間樹的任一結點時,總是先判斷該結點是否肯定不包含問題的解。如果肯定不包含,則跳過

對以該結點為根的子樹的系統搜索,逐層向其祖先結點回溯。否則,進入該子樹,繼續按深度優先的策略進行搜索。回溯法在用來

求問題的所有解時,要回溯到根,且根結點的所有子樹都已被搜索遍才結束。而回溯法在用來求問題的任一解時,只要搜索到問題

的一個解就可以結束。這種以深度優先的方式系統地搜索問題的解的算法稱為回溯法,它適用於解一些組合數較大的問題.

針對所給問題,一般的解題步驟為:確定問題的解空間 --> 確定結點的擴展搜索規則--> 以DFS方式搜索解空間,並在搜索過程中用剪枝函數避免無效搜索。

Prime ring problem

題目描述

A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.

Note: the number of first circle should always be 1.

技術分享圖片

輸入描述:

n (0 < n < 20).
       

輸出描述:

The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.
       

You are to write a program that completes above process.

Print a blank line after each case.
示例1

輸入

6
8

輸出

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

這道題是素數環問題,大意是由給定的1到n數字中,將數字依次填入環中,使得環中任意兩個相鄰的數字間的和為素數。
對於給定的n,按字典序由小到大輸出所有符合條件的解(第一個數恒定為1)
在這裏可以采用回溯法枚舉每一個值。當第一個數位為1確定時,嘗試放入第二個數,使其與1的和為素數,放入後再嘗試
放入第三個數,使其與第二個數的和為素數,直到所有的數全部放入環中,且最後一個數與1的和也是素數,則得到答案,輸出。
若在嘗試放數的過程中,發現當前位置無論放置任何之前未被使用的數均不可能滿足條件,那麽回溯改變其上一個數,直到產生
所需要的答案或不存在更多的解。
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 
 4 int ans[22];   //保存環中被放入的數
 5 int mark[22];  //標記之前被放入環中的數
 6 int n;
 7 int prime[]={2,3,5,7,11,13,17,19,23,29,31,37};//40內得素數,用於判斷是否是素數
 8 
 9 int Judge( int x)
10 {
11     //判斷一個數是否是素數
12     int i;
13     for( i=0; i<12; i++){
14         if( prime[i]==x) return 1;
15     }
16     return 0;
17 }
18 
19 void Check()
20 {
21     //檢查輸出由回溯法枚舉得到的解
22     int i;
23     if( Judge(ans[n]+ans[1])==0) return;//判斷最後一個數與第一個數的和是否是素數
24     for( i=1; i<=n; i++){
25         if( i!=1) printf(" ");
26         printf("%d",ans[i]);
27     }
28     printf("\n");
29 }
30 
31 void DFS( int num)
32 {
33     //遞歸枚舉,num為當前已經放入環中的數字
34     int i;
35     if( num>1 ) if( Judge(ans[num]+ans[num-1])==0 ) return;
36 
37     if( num==n ){
38         //若已經放入n個數
39         Check();
40         return;
41     }
42     for( i=2; i<=n; i++){
43         if(mark[i]==0){
44             mark[i]=1;  //標記i為已經使用
45             ans[num+1] = i;  //將這個數字放入ans數組中
46             DFS( num+1 );
47             mark[i] = 0; //重新標記為未使用
48         }
49     }
50 }
51 
52 int main()
53 {
54     int cnt=0;  //記錄case數
55     int i;
56     while( scanf("%d",&n)!=EOF){
57         cnt++;
58         for( i=0; i<22; i++) mark[i] = 0;  //初始化
59         ans[1] = 1;
60         printf("Case %d:\n",cnt);
61         mark[1] = 1;
62         DFS(1);
63         printf("\n");
64     }
65     return 0;
66 }







回溯枚舉法