您的位置:首页 > 编程语言

巧排数字,将1,2,...,19,20这20个数字排成一排,使得相邻的两个数字之和为一个素数,且首尾两数字之和也为一个素数。编程打印出所有的排法。

2010-03-28 09:31 776 查看
#include "stdafx.h"
#include <iostream>

const int nTable[21][21] =
{
// 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 3, 0, 5, 0, 7, 0, 0, 0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0}, //1
{0, 3, 0, 5, 0, 7, 0, 0, 0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0}, //2
{0, 0, 5, 0, 7, 0, 0, 0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23}, //3
{0, 5, 0, 7, 0, 0, 0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0}, //4
{0, 0, 7, 0, 0, 0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0}, //5
{0, 7, 0, 0, 0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0}, //6
{0, 0, 0, 0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0}, //7
{0, 0, 0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0}, //8
{0, 0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29}, //9
{0,11, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0}, //10
{0, 0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31}, //11
{0,13, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31, 0}, //12
{0, 0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31, 0, 0}, //13
{0, 0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31, 0, 0, 0}, //14
{0, 0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31, 0, 0, 0, 0}, //15
{0,17, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31, 0, 0, 0, 0, 0}, //16
{0, 0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31, 0, 0, 0, 0, 0,37}, //17
{0,19, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31, 0, 0, 0, 0, 0,37, 0}, //18
{0, 0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31, 0, 0, 0, 0, 0,37, 0, 0}, //19
{0, 0, 0,23, 0, 0, 0, 0, 0,29, 0,31, 0, 0, 0, 0, 0,37, 0, 0, 0} //20
};
int nStack[250] = {0}; // 堆栈
int ps = 0; // 栈指针
int nResult[20] ={0}; // 结果
int pr = 0; // 结果指针
void push(int l, int h)
{
nStack[ps] = ((l<<8)&0xff00)|(h&0xff);
ps++;
}

void pop(int&l, int&h)
{
ps--;
l = (nStack[ps]>>8)&0xff;
h = nStack[ps]&0xff;
}

void Init()
{
push(0,0);
/* for(int i=1;i<=20;i++)
{
for(int j=1;j<=20;j++)
if(nTable[i][j]>0)
{
push(i,j);
}
}
*/ push(1,2);
pr = 0;
}

int main(int argc, char* argv[])
{
Init();
int x = 0,y = 0;
bool bPush = true;
unsigned long nTotal = 0;
while(1)
{
start:
pop(y, x);
while(x==21 && y==21)
{
pr--;
pop(y, x);
}

if((x==0) && (y==0))
break;

for(int mm= 0;mm<pr;mm++)
{
if(nResult[mm] == x) // 不允许重复
{
goto start;
}
}

if( pr == 19 )
{
nResult[pr] = x;
{
/* printf("------------------------------------------");
printf("/n");
for(int kk= 0;kk<20;kk++)
printf("%d ", nResult[kk]);
printf("/n");
printf("------------------------------------------");
printf("/n");
*/
nTotal++;
}
goto start;
}

push(21,21);
for(int i= 1;i<=20;i++)
{
if(nTable[x][i]>0)
{
push(x,i);
}
}

nResult[pr] = x;
pr++;
}

printf ("total = %d", nTotal);
getchar();
return 0;
}

我的总体思想就是根据所有20个数的和建20X20的表,表中和为非素数的项置零,整个问题的求解就归结为递归遍历所有表项,在20列中查找出所有非零值的项数的排列组合,初始将表中所有非零项入栈,并将21,21这个值压入栈中做为每一项的分隔符,栈的大小可估算为:初始表项+(每列表项+1)X20.

只打2开头的一种排列..打出了10339131种排列,大约用时3分钟,有耐心的兄弟试下,初步估计,打印出全集要跑4-5小时左右.(表中有一百项),针对我的算法还可以进一步优化,但空间不大,有时间再想一想,目前主要感觉在递归比较上浪费了好多时间.

在网上也查了下,有人说这可以归结成20个无向结点的汉密尔顿回路问题,不知算法上会不会比我这个要快.有时间研究下,或者哪位兄台做过的可以回贴告知下,呵呵...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐