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