1. 程式人生 > >將1、2、...、20這20個數排成一排,使得相鄰的兩個數之和為一個素數,且首尾兩數字之和也為一個素數。

將1、2、...、20這20個數排成一排,使得相鄰的兩個數之和為一個素數,且首尾兩數字之和也為一個素數。

這裡提供了三種方法:
(注意:為了讓程式更快,根據排列的特點,每種方法都固定了最後一個元素,這樣輸出只是滿足條件中的一部分,但是你可以修改每種方法中的輸出,所有元素通過移動一個位置來輸出, 如123,第一次輸出123,第2次231,第3次312,這樣就可以得到所有的解。)

下面只對其中的暴力方法做簡單的說明。
暴力方法思想:對1-n做出所有的排列,然後依次檢查每個排列看是否滿足條件,滿足的輸出。
其中的遞迴只是做出排列。排列遞迴的思想就是,任選1到n中的一個放到最後位置,(遞迴)任選剩餘的數中的一個放到次後位置,*** ,按照這樣迴圈下去。
順便提一下,這種方法很慢,做完所有排列要進行遞迴幾十億億次,你要等很久(可能久到幾個小時,哈哈)才能看到結果。  但是,你可以把我註釋的for語句代替其下的for可以快一點看到結果。
具體看程式碼中的解釋。

看懂暴力方法,就能看懂方法三了。一就不用看了,可能你也看不懂。雖然它的速度是這三個比較快的一個,但理解也更難。

如果這樣你都看不懂,那麼是你的問題了,可能你根本不知道什麼是排列,也可能你根本不知道什麼是遞迴,一切都是白說。(那樣你應該找本書看,而不是光問。)

#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <math.h>
#include <time.h>

bool IsPrimeNumber(int n)
{ /*判斷素數*/
int i; 
int sqrootN; 
if ( n == 2 ) { 
  return true; 
} else if ( n%2 == 0 || n==1 ) { 
  return false; 

sqrootN = (int)( sqrt(n)+0.1 )+1; 
i = 3; 
while ( i < sqrootN ) { 
  if (n%i == 0) {
   return false; 
  }
  i += 2; 

return true; 


void Swap(int *a, int *b) 
{ /*交換兩數*/
int tmp; 
tmp = *a; 
*a = *b; 
*b = tmp; 


bool IsOk(int *arr, int arrsize) 
{ /*判斷是否滿足條件*/
if ( !IsPrimeNumber(arr[arrsize-1]+arr[0]) ) { 
  return false; 


while( --arrsize > 0 ) { 
  if ( !IsPrimeNumber(arr[arrsize]+arr[arrsize-1]) ) { 
   return false; 
  } 

return true; 


////////////////////////////////////////////////////////
// 方法一:
bool Adjust_Pair(int *arr, int arrsize,  int depth) 

static int total=0; 
bool ret = false; 
int i; 
if ( depth==2 ) { 
  if ( IsPrimeNumber(arr[0]+arr[arrsize-1]) ) { 
   total++; 
   printf("\n%03d: ",total);
   for( i=0; i<arrsize; i+=2 ) { 
    printf("%02d-%02d ", arr[i], arr[i+1]); 
   } 
   return true; 
  } else { 
   return false; 
  } 

for (i=depth-2; i>1; i-=2) { 
  if ( IsPrimeNumber(arr[i-1]+arr[depth-2]) ) { 
   Swap(arr+depth-3, arr+i-1); 
   Swap(arr+depth-4, arr+i-2); 
   if ( Adjust_Pair(arr, arrsize, depth-2) ) { 
    ret = true; 
   } 
   Swap(arr+depth-3, arr+i-1); 
   Swap(arr+depth-4, arr+i-2); 
  } 

return ret; 


bool Make_Pair(int *arr, int arrsize, int depth) 

bool ret = false; 
int i; 
static int total1=0; 
static int total2=0; 
if ( depth==0 ) {  
  return Adjust_Pair(arr, arrsize, arrsize); 


for( i=0; i<depth-1; i+=2 ) { 
  if ( IsPrimeNumber(arr[depth-1]+arr[i]) ) { 
   Swap(arr+depth-2, arr+i); 
   if ( Make_Pair(arr, arrsize, depth-2) ) { 
    ret = true; 
   } 
   Swap(arr+depth-2, arr+i); 
  }

return ret; 

void DoPermutation(int *arr, int arrsize) 
{
if(arrsize%2==1) { 
  printf("\n結果:不存在(陣列大小必須為偶數)."); 
  return;


if ( !Make_Pair(arr, arrsize, arrsize) ) { 
  printf("\n結果:不存在."); 



//////////////////////////////////////////////////////
//暴力方法:無條件進行所有排列,並逐一判斷是否滿足條件
bool _DoPermutation2(int *arr, int arrsize, int depth) 

static int total=0; 
bool ret = false; 
int i; 
if ( depth==0 ) { /*排列完成*/
  if ( IsOk(arr, arrsize) ) { /*判斷是否滿足條件, 滿足條件就輸出*/
   total++; 
   printf("\n%03d: ",total);
   for( i=0; i<arrsize; i+=2 ) { 
    printf("%02d-%02d ", arr[i], arr[i+1]); 
   } 
   return true; 
  } else { 
   return false; 
  } 


/* for (  i=(depth+1)%2; i<depth; i+=2  ) { 將下面for換成這個for可以優化一半的速度*/
for (  i=0; i<depth; i++  ) { /*depth-1相當於陣列的最後一個位置*/
  Swap(arr+depth-1, arr+i); /*選擇arr[i]到放到陣列的最後一個位置arr[depth-1]*/
  if ( _DoPermutation2(arr, arrsize, depth-1) ) { /*遞迴排列前depth-1個元素*/
   ret = true; 
  } 
  Swap(arr+depth-1, arr+i); /*交換回來,讓原來的陣列不變*/

return ret; 


void DoPermutation2(int *arr, int arrsize) 
{
if(arrsize%2==1) { 
  printf("\n結果:不存在(陣列大小必須為偶數)."); 
  return;


if ( !_DoPermutation2(arr, arrsize, arrsize-1) ) { 
  printf("\n結果:不存在."); 



//////////////////////////////////////////////////////
// 方法三:當且僅當正在進行的排列滿足部分條件時,進行遞迴
bool _DoPermutation3(int *arr, int arrsize, int depth) 

static int total=0; 
bool ret = false; 
int i; 
if ( depth==0 ) { 
  if ( IsPrimeNumber(arr[arrsize-1]+arr[0]) ) { 
   total++; 
   printf("\n%03d: ",total);
   for( i=0; i<arrsize; i+=2 ) { 
    printf("%02d-%02d ", arr[i], arr[i+1]); 
   } 
   return true; 
  } else { 
   return false; 
  } 


for (  i=(depth+1)%2; i<depth; i+=2  ) { 
/* for (  i=0; i<depth; i++  ) { 將上面換成這句也可以,但上面更好*/
  if ( !IsPrimeNumber(arr[depth]+arr[i]) ) { 
   continue; 
  } 
  Swap(arr+depth-1, arr+i); 
  if ( _DoPermutation3(arr, arrsize, depth-1) ) { 
   ret = true; 
  } 
  Swap(arr+depth-1, arr+i); 

return ret; 


void DoPermutation3(int *arr, int arrsize) 
{
if(arrsize%2==1) { 
  printf("\n結果:不存在(陣列大小必須為偶數)."); 
  return;


if ( !_DoPermutation3(arr, arrsize, arrsize-1) ) { 
  printf("\n結果:不存在."); 



int main(int argc, char* argv[])
{
clock_t start, finish;
int arr[100],i; 
for( i=0; i<100; i++ ) { 
  arr[i]=i+1; 


/*方法一*/
DoPermutation(arr, 18); 
/*暴力方法*/
/*DoPermutation2(arr, 18);*/ 
/*方法三*/
/*DoPermutation3(arr, 18); */

return 0;
}