1. 程式人生 > >(回溯Uva524)素數環

(回溯Uva524)素數環

題目

輸入正整數,把整數1,2,3,···,n組成一個環,使得相鄰兩個整數之和均為素數。輸出時從整數1開始逆時針排列。同一個環應恰好輸出一次。n<=16
樣例輸入
6
樣例輸出
1 4 3 2 5 6
1 6 5 2 3 4

分析與解答

用一個數組a存答案,由於是從1開始,a[0]=1,

void DFS ( Vertex V )
{
     visited[ V ] = true;
     if(…) return;
     for ( V 的每個鄰接點 W )
         if ( !visited[ W ] )
             DFS( W );
}

在這個題中,深搜需要的終止條件,l==n&&isp[A[0]+A[n-1]],l是位置,如果已確定了n個位置,說明此時終止,並且如果第一個a[0]等於a[n-1]說明此時終止,終止的話,從0到n-1輸出即可
如果不滿足終止條件,我們就找新的數填到位置l,然後遞迴找下一個位置需要填的數,如何知道該位置填什麼數?我們知道第一個數是1,那這個位置的數我們假設是2到n中任一個,迴圈,如果滿足這個數不曾出現而且和上一個位置的數之和為素數,那我們就把這個位置填上這個數,把標記陣列標記用來表明這個數已經被用過,並且遞迴呼叫找下個位置,我們遞迴完了還要清除標記陣列的標記,就像是找到了一個可能情況,就不斷地回溯一樣,這樣的話最終會找出所有情況

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int is_prime(int x) {
  for(int i = 2; i*i <= x; i++)
    if(x % i == 0) return 0;
  return 1;
}

int n, A[50], isp[50], vis[50];

void dfs(int l){
    if(l==n&&isp[A[0]+A[n-1
]]){ for(int i=0;i<n;++i) if(i==0) printf("%d",A[i]); else printf(" %d",A[i]); printf("\n"); } else{ for(int i=2;i<=n;++i) if(!vis[i]&&isp[i+A[l-1]]){ A[l]=i; vis[i]=1; dfs(l+1); vis[i]=0; } } } int main() { int kase = 0; for(int i = 2; i <= 20*2; i++) isp[i] = is_prime(i); while(scanf("%d", &n) == 1 && n > 0) { printf("Case %d:\n", ++kase); memset(vis, 0, sizeof(vis)); A[0] = 1; dfs(1); printf("\n"); } return 0; }