任意阶幻方

 

幻方

幻方简介

起源:易经

别名:河图,洛书,纵横图。

 

  • 定义:幻方是一种将数字安排在正方形格子中使每行,列和对角线上的数字都相等的方法。

    种类:

    • 完全幻方:一个幻方行,列,主对角线及范对角线各数之和均相等。

    • 乘幻方:指一个幻方行,列对角线个数乘积相等。

    • 高次幻方:高次幻方指,当组成幻方各数替换为其2,3,……,k,……次幂时,仍满足幻方条件的。

    • n阶幻方:指由前n^2个自然数组成的一个n阶方阵,各行各列及两条对角线所含的n个数的和相等。

      如三阶幻方:

      816
      357
      492
    • 反幻方:在一个由若干个排列整齐的数组成的正方形中,其中任意一横行、一纵行及对角线的几个数之和不相等,具有这种性质的图表,称为“反幻方”。

幻方的制作(完全)

奇数幻方

方法二:杨辉法

九子斜排,上下对易,左右相更,四维推进;戴九履一,左三右气,二四为肩,六八为足。

解释:

九子斜排,

1
42
753
86
9

上下对易,左右相更

9
42
357
86
1

四维推进

492
357
816

方法二:罗伯法(楼梯法)

:一居上行正中央,依次斜填切莫忘;上出框时向下放,右出框时向左放;排重便在下格填,右上排重一个样。

代码

一居上行正中央:将数字1放到幻方第一行,中间一列

010
000
000

依次斜填切莫忘,上出框时向下放,右出框时向左放:从第一个数1开始,向左上(或右上)填数字,从上边超出边界时,放到最下面一行对应的列,重左边超出边界时,放到最右面一行对应的列。

010
003
200

排重便在下格填,右上排重一个样:如果要填入的数字被占了,则填到基准数字的下面。(如数字4的填法)

010
003
204

代码如下:

#include<iostream>
using namespace std;
int main()
{
    int n,a[100][100]={0},x,y,i,j,k;
    cin>>n;
    j=n/2;
    i=0;
    a[i][j]=1;
    for(k=2;k<=n*n;k++)
    {
        x=--i;
        y=--j;
        if(i<0)
        i=n-1;
        if(j<0)
        j=n-1;
        if(a[i][j]!=0)
        {
            i=x+2;
            j=y+1;
        }
         a[i][j]=k;
    }
    for(i=0;i<n;i++)
    {
    for(j=0;j<n;j++)
    {
        cout<<a[i][j]<<"\t";
    }
    cout<<endl<<endl;
    }
    return 0;
 } 

双偶幻方(阶数为4的整数倍):

方法:Spring法

  • 先按顺序将数字填到幻方框架中(以8阶幻方为例)。

    如下图

     

  • 然后将将数字分为4个小正方形(如图红线所分)后小正方形对角线上的数字,在大正方形上以中心对称的方式进行交换,(就是将原来的数字m换为数字n*n+1-m)(n为阶乘数)

 

  • 2交换完成就得到幻方

 

#include<iostream>
#include<math.h>
using namespace std;
int a[100][100];
void two_even_numbers(int n)//双偶数幻方 4*n
{
    int num=1;
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    a[i][j]=num++;//按顺序输入 
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    {
        if(i%4==0&&abs(i-j)%4==0)
            for(int k=0;k<=3;k++)
            {
                a[i+k][j+k]=n*n+1-a[i+k][j+k];//给小四边形的对角线赋值,由左上至右下 
            }
        if(i%4==3&&(i+j)%4==3)
            for(int k=0;k<=3;k++)
            {
                a[i-k][j+k]=n*n+1-a[i-k][j+k];//给小四边形的对角线赋值,由左下至右上 
            }
    } 
}
int main ()
{
    int n;
    cin>>n;
    two_even_numbers(n);
    for(int i=0;i<n;i++)
    {
    for(int j=0;j<n;j++)
    cout<<a[i][j]<<"\t";
    cout<<endl<<endl<<endl;
    }
    return 0;
 } 

单偶幻方(4n+2):斯特雷奇法

  • 首先将n阶幻方分为四个区域,1为左上,2为右下,3为右上,4为左下,然后按区域按顺序填入数字。

     

  • 然后将每个区域数字按奇数阶幻方的填法进行填表。(如下)

  •  

  • 然后将绿色框内的数字和红色框内的对应位置的数字交换。

     

  • 交换完成后得到幻方。

  •  

代码如下

//斯特雷奇法 
#include<iostream>
#include<math.h>
using namespace std;
int a[100][100]={0};
//罗伯法,填小奇数幻方 
int change1(int begin_point_x,int begin_point_y,int end_point_x,int end_point_y,int length,int number)
{
    int k,z,w;
    //赋值起点坐标 
    int i=begin_point_x;
    int j=begin_point_y+length/2;
    //赋起点值 
    a[i][j]=number;
    //构造幻方 
        for(k=++number;k<=number+length*length-2;k++)//判断循环次数 
        {
            z=i,w=j; 
            i--;
            j++;
            z=i,w=j; 
            if(i<begin_point_x) //判断是否出界 
            i=end_point_x;
            if(j>end_point_y)//
            j=begin_point_y;
            //判断该位置是否有被赋值 
            if(a[i][j]!=0)
            {
                 i=z+2;
                 j=w-1;
            }
            a[i][j]=k;
         }
}
//进行位置交换 
void change2(int n)
{
    int k=(n-2)/4;
    int t;
    for(int i=0;i<n/2;i++)
    {
        for(int j=0;j<k;j++)//左半边幻方进行交换 
        {
            if(i==n/4)
            {
            t=a[i][j+k];
            a[i][j+k]=a[i+n/2][j+k];
            a[i+n/2][j+k]=t;
            }
            else
            {
            t=a[i][j];
            a[i][j]=a[i+n/2][j];
            a[i+n/2][j]=t;
            }
        }
        for(int j=0;j<k-1;j++)//右半边幻方进行交换 
        {
            int m=j+n/2+n/4;
            t=a[i][m];
            a[i][m]=a[i+n/2][m];
            a[i+n/2][m]=t;
        }
    }
}
int  judge(int n)//判断输出是否正确 
{
    int num1=0,k=1,num2=0;
    for(int i=0;i<n;i++)
        num1+=a[0][i];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            num2+=a[i][j];
        }
        if(num2!=num1)
        k=0;
        num2=0;
    }
    for(int j=1;j<n;j++)
    {
        for(int i=0;i<n;i++)
        {
            num2+=a[i][j];
        }
        if(num2!=num1)
        k=0;
        num2=0;
    }
    return k;
 } 
int main()
{
    int n;
    cin>>n;
    int num=n/2;
    //左上区 
    change1(0,0,num-1,num-1,n/2,1);
    change1(num,num,n-1,n-1,n/2,num*num+1);
    change1(0,num,num-1,n-1,n/2,num*num*2+1);
    change1(num,0,n-1,num-1,n/2,num*num*3+1);
    change2(n);
    if(judge(n)==0)
    cout<<"error"<<endl;
    else
    for(int i=0;i<n;i++)
    {
    for(int j=0;j<n;j++)
        {
            cout<<a[i][j]<<"\t";
        }
        cout<<endl<<endl<<endl;
    }
    return 0;   
}

任意阶幻方

#include<iostream>
#include<math.h>
using namespace std;
int a[100][100];
//罗伯法,构造奇数幻方小奇数幻方 
int change1(int begin_point_x,int begin_point_y,int end_point_x,int end_point_y,int length,int number)
//初始点坐标,结束点坐标,阶数,初始数据 
{
    int k,z,w;
    //赋值起点坐标 
    int i=begin_point_x;
    int j=begin_point_y+length/2;
    //赋起点值 
    a[i][j]=number;
    //构造幻方 
        for(k=++number;k<=number+length*length-2;k++)//判断循环次数 
        {
            z=i,w=j; 
            i--;
            j++;
            z=i,w=j; 
            if(i<begin_point_x) //判断是否出界 
            i=end_point_x;
            if(j>end_point_y)//
            j=begin_point_y;
            //判断该位置是否有被赋值 
            if(a[i][j]!=0)
            {
                 i=z+2;
                 j=w-1;
            }
            a[i][j]=k;
         }
}
//在使用罗伯法对单偶幻方的四个部分处理后,使用此法进行位置交换,构造双偶幻方 
void change2(int n)
{
    int k=(n-2)/4;
    int t;
    for(int i=0;i<n/2;i++)
    {
        for(int j=0;j<k;j++)//左半边幻方进行交换 
        {
            if(i==n/4)
            {
            t=a[i][j+k];
            a[i][j+k]=a[i+n/2][j+k];
            a[i+n/2][j+k]=t;
            }
            else
            {
            t=a[i][j];
            a[i][j]=a[i+n/2][j];
            a[i+n/2][j]=t;
            }
        }
        for(int j=0;j<k-1;j++)//右半边幻方进行交换 
        {
            int m=j+n/2+n/4;
            t=a[i][m];
            a[i][m]=a[i+n/2][m];
            a[i+n/2][m]=t;
        }
    }
}
//双偶幻方函数,海尔法 
void two_even_numbers(int n)
{
    int num=1;
    //初始化数据 
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    a[i][j]=num++; 
    //进行交换
    int m=n*n+1; 
    int k;
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
     {
        if(i%4==0&&abs(i-j)%4==0)
        for(int k=0;k<4;k++)
        {
            a[i+k][j+k]=m-a[i+k][j+k];
         }
         else if(i%4==3&&(i+j)%4==3)
          for(int k=0;k<4;k++)
         {
            a[i-k][j+k]=m-a[i-k][j+k];
         }      
        }
 } 
//判断是否为幻方 
int  judge(int n)
{
    int num1=0,k=1,num2=0;
    for(int i=0;i<n;i++)
        num1+=a[0][i];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            num2+=a[i][j];
        }
        if(num2!=num1)
        k=0;
        num2=0;
    }
    for(int j=1;j<n;j++)
    {
        for(int i=0;i<n;i++)
        {
            num2+=a[i][j];
        }
        if(num2!=num1)
        k=0;
        num2=0;
    }
    return k;
 } 
// 输出幻方
void print(int n) 
{
    for(int i=0;i<n;i++)
    {
    for(int j=0;j<n;j++)
        {
            cout<<a[i][j]<<"\t";
        }
        cout<<endl<<endl<<endl;
    }
}
int main()
{
    int n;
    while(1)
    { 
    cout<<"请输入你需要的幻方阶数,如果你想要结束请输入0:";
        cin>>n;
        if(n==0)
        return 0;
         for(int i=0;i<n;i++)
         for(int j=0;j<n;j++)
         a[i][j]=0;
        int num=n/2;
        if(n%4!=0&&n%2==0)
        {
        //单偶幻方 
        change1(0,0,num-1,num-1,n/2,1);
        change1(num,num,n-1,n-1,n/2,num*num+1);
        change1(0,num,num-1,n-1,n/2,num*num*2+1);
        change1(num,0,n-1,num-1,n/2,num*num*3+1);
        change2(n);
        }
        else if(n%2==1)
        {
        //奇数阶幻方 
        change1(0,0,n-1,n-1,n,1);
        }
        //双偶幻方 
        else if(n%4==0)
        {
        two_even_numbers(n);
        }
        if(judge(n)==0)//判段幻方是否正确,如果正确输出 
        cout<<"error"<<endl;
        else
        print(n);
   }
    return 0;   
}

参考:百度百科

华中师范刘攀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值