穷举算法—素数幻方

                                                         素数幻方

1.  案例提出

         通常的n阶幻方由1,2,...,n2构成的各行、各列与两对角线之和均相等n行n列方阵。素数幻方全是由素数构成的各行、各列与两对角线之和均相等方阵。

试寻求9个素数,构造一个3阶素数幻方,使得该素数方阵中3行、3列与两对角线上的3个素数之和均等于给定的整数s。

2. 设计要点

     (1) 数学建模

设幻方正中间数为n,幻和(即每行,每列与每对角线之和)为s。注意到

(中间一行)+(中间一列)+2*(两对角线)=6s

(上下行)+(左右列)=4s

两式相减即得

6n=2s → n=s/3                                               (1)

这意味着凡含n的行或列或对角线的三数中,除n之外的另两数与n相差等距。为此,设3阶幻方为: 

        n-x  n+w  n-y

        n+z   n   n-z                                              (2)

        n+y  n-w  n+x

 同时设方阵的两对角线的三数为大数在下(即x,y>0),下面一行三数为大数在右(即x>y)。这样约定是避免重复统计解。

显见,上述3×3方阵的中间一行,中间一列与两对角线上三数之和均为3n。要使左右两列,上下两行的三数之和也为3n,当且仅当

     z=x-y

     w=x+y   (x>y)                                              (3)

同时易知9个素数中不能有偶素数2,因而x,y,z,w都只能是正偶数。

     (2) 穷举设计

对于键盘输入的整数s, 如果存在幻和为s的素数幻方,则s应为中间素数的3倍。若s不是3的整数倍,则对输入的s,输出“无解!”而退出。

设置a数组,数组元素清“0”。通过试商判别,寻找出[3,s]中的所有素数k,并标注a[k]=1,为以后的判断提供依据。

设n=s/3,若a[n]==0,知n不是素数,显然不存在幻和为s的素数幻,显示“无解!”后退出。

设幻方中的素数下界为c,上界为d。显然c=3,注意到d+n+c=s,则d≤2n-3。

注意到 n-y≥3,(n+y)+n+(n-y)=s  得 2n+y=s-(n-y)≤s-3  即 y≤s-2n-3

同理  x≤s-2n-3=n-3

在[2,n-3]中穷举y,在[y+2,n-3]穷举x,并按上述(3)式得z,w:

若出现x=2y,将导致z=y,方阵中出现两对相同的数,显然应予排除。

显然n-w是9个数中最小的,n+w是9个数中最大的。若n-w<c或n+w>d,已超出[c,d]界限,应予以排除。

检测方阵中其他8个数n-x,n+w,n-y,n+z,n-z,n+y,n-w,n+x是否同时为素数,引用变量t1,t2,t1*t2为8个数的标记之积。若t1*t2=0,即8个数中存在非素数,返回。否则,已找到一个三阶素数幻方解,按方阵格式输出并用变量m统计基本解的个数。这样处理,能较快的找出所有解,既无重复,也没有遗漏。

//此题重在数学分析

3.  程序实现

// 指定幻和的三阶素数幻方

#include<stdio.h>
#include<math.h>
void main()
{
int c,d,j,k,t,n,t1,t2,s,w,x,y,z,m;
int a[3000];
printf("请确定素的幻方和s:");
scanf("%d",&s);
if(s%3>0)
{
printf("不存在幻方和为%d的素数比方!\n",s);
return;

}
n=s/3;
m=0;
// 确定幻和为s时素数的最大最小区间  
c=3;
d=2*n-3;   
for(k=c;k<=d;k++)
a[k]=0;
for(k=c;k<=d;k+=2)
{
for(t=0,j=3;j<=sqrt(k);j+=2)
if(k%j==0)
{
t=1;
break;
}
if(t==0)
a[k]=1;   // [c,d]中的奇数k为素数,标注1
}
if(a[n]==0)
{
printf("不存在幻方和为%d的素数方!\n",s);
return;

}
for(y=2;y<=n-3;y+=2)
for(x=y+2;x<=n+3;x+=2)
{
z=x-y;
w=x+y;
if(x==2*y||n-w<c||n+w>d)
continue;    // 控制幻方的素数范围  
// 控制其余8个均为素数 
t1=a[n-w]*a[n+w]*a[n-z]*a[n+z];
t2=a[n-x]*a[n+x]*a[n-y]*a[n+y];
if(t1*t2==0)
continue;
m++;
printf("No %d:\n",m);
   printf("%5d%5d%5d\n",n-x,n+w,n-y);
            printf("%5d%5d%5d\n",n+z,n,n-z);
            printf("%5d%5d%5d\n",n+y,n-w,n+x);
}
printf("\n共有%d个素数幻方.\n",m);
}

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值