巧排数字,将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个无向结点的汉密尔顿回路问题,不知算法上会不会比我这个要快.有时间研究下,或者哪位兄台做过的可以回贴告知下,呵呵...
#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个无向结点的汉密尔顿回路问题,不知算法上会不会比我这个要快.有时间研究下,或者哪位兄台做过的可以回贴告知下,呵呵...
相关文章推荐
- 巧排数字,将1,2,...,19,20这20个数字排成一排,使得相邻的两个数字之和为一个素数
- 巧排数字,将1,2,...,19,20这20个数字排成一排,使得相邻的两个数字之和为一个素数
- 将1、2、...、20这20个数排成一排,使得相邻的两个数之和为一个素数,且首尾两数字之和也为一个素数。
- 从1到20个数字排成一圈,每两个相邻数字之和为一个素数
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。 找出这两个数字,编程实现
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。 找出这两个数字,编程实现。
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。 找出这两个数字,编程实现。
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次,找出这两个数字,编程实现。
- 将1,2,3,。。。,20这20个连续的自然数排成一圈,使任意两个相邻的自然数之和均为素数。
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。 找出这两个数字,编程实现
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。 找出这两个数字,编程实现
- 编程:用java 语言实现,输入一个数,就相应地输出的几维数组!||用1、2、2、3、4、5这六个数字,用java写一个函数,打印出所有不同的排列,要求:"4"不能在第三位,"3"与"5"不能相连
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次,找出这两个数字,编程实现
- .一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。 找出这两个数字,编程实现。
- 把从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数
- 一个数组中只有两个数字是出现一次,其他所有数字都成对出现,找出这两个数字,编程实现
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。找出这两个数字,编程实现。
- C语言- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次,找出这两个数字,编程实现。
- 第一题:有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。 找出这两个数字,编程实现。