将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;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值