这里提供了三种方法:
(注意:为了让程序更快,根据排列的特点,每种方法都固定了最后一个元素,这样输出只是满足条件中的一部分,但是你可以修改每种方法中的输出,所有元素通过移动一个位置来输出, 如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、2、...、20这20个数排成一排,使得相邻的两个数之和为一个素数,且首尾两数字之和也为一个素数。
最新推荐文章于 2021-03-26 04:40:22 发布