将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: 可以使用Kadane算法来解决这个问题。Kadane算法是一个经典的动态规划算法,用于查找数组中的最大子数组和。 具体算法如下: 1. 初始化个变量max_so_far和max_ending_here为0。 2. 遍历数组,对于每个元素,执行以下步骤: a. 将max_ending_here加上当前元素的值。 b. 如果max_ending_here小于0,则将其重置为0。 c. 如果max_so_far小于max_ending_here,则将max_so_far设置为max_ending_here。 3. 返回max_so_far。 对于这个问题,我们可以将原始数组复制一份拼接到原数组的末尾,然后使用Kadane算法在新数组中查找最大子数组和。注意,因为题目要求的是连续的一段数串,所以在拼接时需要保证最后一个元素和第一个元素不相邻。 下面是实现代码: ```c #include <stdio.h> #include <stdlib.h> int maxSubArray(int* nums, int numsSize) { int maxSoFar = 0; int maxEndingHere = 0; for (int i = 0; i < numsSize; i++) { maxEndingHere += nums[i]; if (maxEndingHere < 0) { maxEndingHere = 0; } if (maxSoFar < maxEndingHere) { maxSoFar = maxEndingHere; } } return maxSoFar; } int maxSum(int* nums, int numsSize) { int* arr = (int*)malloc(sizeof(int) * numsSize * 2); int max = nums[0]; for (int i = 0; i < numsSize * 2; i++) { int j = i % numsSize; arr[i] = nums[j]; if (i >= numsSize && i < numsSize * 2 - 1) { int sum = maxSubArray(arr + i - numsSize + 1, numsSize); if (sum > max) { max = sum; } } } free(arr); return max; } int main() { int nums[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; int numsSize = sizeof(nums) / sizeof(nums[0]); int max = maxSum(nums, numsSize); printf("%d\n", max); // 输出6,对应的数串为[4, -1, 2, 1] return 0; } ``` ### 回答2: 题目中给定了一个由N个数组成的圆形数组,要求找到一个连续的子数组,使得该子数组的和为最大,接下来我将用C语言实现这个问题。 假设给定的圆形数组为arr,长度为N。首先我们可以先求出整个数组的和sum。然后需要考虑种情况: 1. 子数组不跨越arr的首尾 首先,我们可以使用Kadane's算法来求解。Kadane's算法用于求解一个普通数组中连续子数组的最大和,其思想是遍历整个数组,在每一步中统计当前位置到当前位置之前的总和(如果是负数则置为0),并与之前的最大总和进行比较,更新最大总和。对于圆形数组,在不跨越首尾的情况下,直接应用Kadane's算法即可。 2. 子数组跨越arr的首尾 对于跨越首尾的子数组,我们可以分为种情况来考虑: a. 子数组包含arr[0] 由于跨越了首尾,所以子数组一定会包含arr[0],即子数组的起始位置在arr[0]之前。在这种情况下,我们可以分为个子问题来求解: - 求出包含arr[0]的最大子数组,即arr[0]与arr[N-1]之间的最大子数组,可以使用Kadane's算法来解决; - 求出arr[1]到arr[N-2]的最小子数组,即不考虑包含arr[0]的情况,直接应用Kadane's算法。 b. 子数组不包含arr[0] 在这种情况下,子数组起始位置在arr[0]之后,终止位置在arr[N-1]之前。对于这种情况,直接应用Kadane's算法即可。 最后,我们在以上的情况中选择一个最大的子数组和即可得到题目所需的结果。 综上所述,使用C语言可以通过以上思路解决这个问题。具体的实现可以根据以上的描述进行编码。 ### 回答3: 问题描述: 给定一个包含N个数的数组,将这些数排列成一个圆环。请找出一个连续的数串,使得该数串的和最大。 解决方法: 要找到使数串和最大的连续一段数串,需要遍历每一个可能的起始位置,并计算以该起始位置开始的连续数串的和。最后比较每个数串的和,找出最大的数串和。 首先,定义一个整型数组nums,并初始化其中的元素。还需要定义变量maxSum和currentSum,用于记录最大的数串和和当前数串和。初始化maxSum为nums[0],currentSum为0。 接下来,使用循环从0到N-1遍历nums数组,遍历的变量记为i。在每次循环开始时,将currentSum重置为0。 在循环中,定义一个变量j,从i开始一直到i+N-1,并使用取模操作确保j的范围在nums的长度内。将currentSum加上nums[j],并通过比较将currentSum更新为当前值或maxSum,取者中的最大值。最后,将maxSum更新为当前最大值。 循环结束后,maxSum保存的即为连续一段数串的最大和。 代码示例: ```c #include<stdio.h> int main() { int N = 6; // 数组元素数量 int nums[6] = {1, -2, 3, -1, 2, -5}; // 初始化数组 int maxSum = nums[0]; // 记录最大的数串和,默认为数组第一个元素 int currentSum = 0; // 记录当前数串的和 for (int i = 0; i < N; i++) { currentSum = 0; // 每次循环前将当前数串和重置为0 for (int j = i; j < i + N; j++) { currentSum += nums[j % N]; // 通过取模操作确保j的范围在数组长度内 if (currentSum > maxSum) { maxSum = currentSum; // 更新最大的数串和 } } } printf("最大的连续一段数串的和为:%d\n", maxSum); return 0; } ``` 以上代码使用层循环实现了计算最大数串和的功能,时间复杂度为O(N^2)。当N的规模较大时,可能会导致计算时间较长。可以通过动态规划的方法将时间复杂度降低到O(N)。但由于题目中未限定N的范围,因此以上方法已经足够解决一般情况下的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值