1. 程式人生 > >c++演算法之回溯 素數環(二)

c++演算法之回溯 素數環(二)

Description

輸入正整數n,把整數1,2,3,…,n組成一個環,使得相鄰兩個整數之和均為素數。把全部的解按字典序排序後,從1開始編號,依次輸出指定編號的k組解。最後一行輸出總的方案數。同一個素數環只算一次。

Input

第1行:2個整數,n(n<=18)和k(1<=k<=10)
第2行:共有k個從小到大排列的整數,表示要輸出的解的編號。

Output

前k行,每行一組解,對應於一個輸入
第k+1行:一個整數,表示總的方案數。

Sample Input

10 4
1 2 5 8
Sample Output
1 2 3 4 7 6 5 8 9 10
1 2 3 4 7 10 9 8 5 6
1 2 3 8 5 6 7 10 9 4
1 2 3 10 9 8 5 6 7 4
96

分析:

演算法思維與(一)一樣,但需要注意這樣兩點(坑點):

1.“把全部的解按字典序排序後,從1開始編號,依次輸出指定編號的k組解。最後一行輸出總的方案數。同一個素數環只算一次。”實現這句話其實就是要固定環的第一個數為1,這樣就可以保證不重複,且按字典序排序。

2.要求輸出指定的k組解,我是在輸出的時候處理的,要統計總數就在那裡自增,再判斷當前解是否是指定的k組解中的,是才輸出

程式實現如下:

#include<cstdio>
#include<cmath>
int a[19],k,sum,n[11],num=1,q;
bool b[19]={0};
bool p(int s)//判斷是否為素數 
{
    for(int i=2;i<=sqrt(s);i++)
    	if(s%i==0) return 0;     
    return 1;                               
}
void print()
{
    sum++;//此時的sum也是此素數環的順序,產生完所有的素數環之後,sum即為所有的組數 
    if(sum==n[num])//如果此時是k組資料,才輸出 
    {
        for(int i=1;i<q;i++)
            printf("%d ",a[i]);
        printf("%d\n",a[q]);
        num++;//num滾動遞增到下一個要求的素數環的序號 
    }
}
int search(int r)
{
    for(int i=2;i<=q;i++)
        if(!b[i]&&p(i+a[r-1]))//沒有被使用過,且與前一個數相加是素數 
    {
        a[r]=i;
        b[i]=1;//儲存並標記 
        if(r==q&&p(1+a[q])) print();//如果填完所有的數,且最後一個數與開頭的數之和為素數 
        else search(r+1);//遞歸回溯 
        b[i]=0;
    }
}
int main()
{
    scanf("%d %d",&q,&k);
    for(int i=1;i<=k;i++)
        scanf("%d",&n[i]);//將k組資料儲存在n陣列中 
    a[1]=1;
    b[1]=1;//將第一個數固定為1,從2開始搜尋 
    search(2);
    printf("%d",sum);//最後輸出總數 
}