zoukankan      html  css  js  c++  java
  • 魔方阵(幻方)构造方法

    C#代码为自行编写 下面的说明内容引用自 http://hi.baidu.com/chisir001/blog/item/47ac9da843b7b5f61f17a2ec.html 有部分修改

    魔方阵,又叫幻方,在我国古代称为“纵横图”。由N2个自然数构成的幻方叫N阶幻方,每行、每列及两对角线上各数之和都相等,令其之和为S,S叫幻方常数,可用公式S=N(N2+1)/2求得。 

    或许读者会问:对于任意给出的正整数n,n阶幻方是否存在?如果存在,怎样把它构造出来?有多少种不同的构造方法? 
    解决这个问题,要分三种情况考虑。 
    第一种情况,N=1或2。N等于1时,输出其不意。N等于2时,不能够成幻方。 
    第二种情况,N=2m+1,m=1,2,3,……此时构成的幻方称为奇阶幻方,它的构成很有规律: 
    (1) 第一个数放在第一行中间位置上 
    (2) 如果K-1为N的整数倍,K就放在K-1的正下方。(放置时,如果K-1在最后一行,K就放到第一行的相应位置) 
    (3) 如果K-1不是N的整数倍,K放在K-1的右上方。(放置时,如果K-1在第一行,则K放到最后一行的相应位置;如果K-1在最后一列,K就放在第一列的相应位置)。 
    第三种情况,N=4m,m=1,2,3,……此时构成的幻方称为双偶阶幻方。 
    构造这样的偶阶幻主,可以先将1~n*n这n*n个数顺次赋给n*n的二维数组A中的元素。
    将左上区域i+j为偶数的与幻方内以中心点为对称点的右下角对角数字进行交换;
    将右上区域i+j为奇数的与幻方内以中心点为对称点的左下角对角数字进行交换。(保证不同时为奇或偶即可。)

    第四种情况,n为偶数,且不能被4整除 (n=6,10,14,18,22……) (n=4k+2,k=1,2,3,4,5……) 此时构成的幻方称为单偶阶幻方。

    单偶阶幻方(斯特雷奇Ralph Strachey法)

    (1) 把方阵分为A,B,C,D四个象限,这样每一个象限肯定是奇数阶。用楼梯法,依次在A象限,D象限,B象限,C象限按奇数阶幻方的填法填数。 
    (2)在A象限的中间行、中间格开始,按自左向右的方向,标出k格。A象限的其它行则标出最左边的k格。将这些格,和C象限相对位置上的数,互换位置。
    (3)在B象限任一行的中间格,自右向左,标出k-1列。(注:6阶幻方由于k-1=0,所以不用再作B、D象限的数据交换), 将B象限标出的这些数,和D象限相对位置上的数进行交换,就形成幻方。

    ABCD为10阶幻方拆分成的4个5阶幻方 A最小 B第三小 C最大 D第二小 所以B=原5阶幻方数字+2*n*n C=原5阶幻方数字+3*n*n D=原5阶幻方数字+n*n

    下图为要交换的A和C的方块

    下图为交换之后的

    下图为选中的要交换的B和D的列 总共要交换(K-1)列

    下图为交换之后的

    以上内容引用自 http://hi.baidu.com/chisir001/blog/item/47ac9da843b7b5f61f17a2ec.html 有部分修改

    对于以上的3种算法 我使用C#进行了实现:

    以下是对于3种算法的工厂类 实现N阶幻方

        class MagicSquareFactory
    {
    public static MagicSquare GetMagicSquare(int size)
    {
    if (size % 2 == 1)
    {
    return new MagicSquare2n1(size);
    }
    else if (size % 4 == 0)
    {
    return new MagicSquare4n(size);
    }
    else
    {
    return new MagicSquare4n2(size);
    }

    }
    }

    以下是3种算法的抽象类:

        public abstract class MagicSquare
    {
    protected int size;
    protected int[,] values;

    public MagicSquare(int size)
    {
    this.size = size;
    CreateMagicSquare();
    }

    protected virtual void CreateMagicSquare()
    {

    }

    public String GetValueString()
    {
    String returnstring = "";
    for (int x = 0; x < size; x++)
    {
    for (int y = 0; y < size; y++)
    {
    returnstring += values[x, y].ToString() + "\t";
    }
    returnstring += "\r\n";
    }
    return returnstring;
    }

    public int[,] GetValueArray()
    {
    return values;
    }

    public String GetCheckString()
    {
    String returnstring = "";
    for (int x = 0; x < size; x++)
    {
    returnstring += "" + x.ToString() + "行总和为:";
    int xsum = 0;
    for (int y = 0; y < size; y++)
    {
    xsum += values[x, y];
    }
    returnstring += xsum.ToString() + "\r\n";
    }


    for (int y = 0; y < size; y++)
    {
    returnstring += "" + y.ToString() + "列总和为:";
    int ysum = 0;
    for (int x = 0; x < size; x++)
    {
    ysum += values[x, y];
    }
    returnstring += ysum.ToString() + "\r\n";
    }

    int sum = 0;

    for (int i = 0; i < size; i++)
    {
    sum += values[i, i];
    }
    returnstring += "从左到右的斜线总和为:" + sum.ToString() + "\r\n";

    sum = 0;
    for (int i = 0; i < size; i++)
    {
    sum += values[i, size-1-i];
    }
    returnstring += "从右到左的斜线总和为:" + sum.ToString() + "\r\n";

    return returnstring;


    }
    }

    2n+1阶幻方的实现类:

        public class MagicSquare2n1 : MagicSquare
    {

    public MagicSquare2n1(int size)
    : base(size)
    {

    }

    protected override void CreateMagicSquare()
    {
    values = new int[size, size];

    /*
    (1) 第一个数放在第一行中间位置上
    (2) 如果K-1为N的整数倍,K就放在K-1的正下方。(放置时,如果K-1在最后一行,K就放到第一行的相应位置)
    (3) 如果K-1不是N的整数倍,K放在K-1的右上方。(放置时,如果K-1在第一行,则K放到最后一行的相应位置;如果K-1在最后一列,K就放在第一列的相应位置)。
    */


    int lastx, lasty;
    values[0, size / 2] = 1;
    lastx = 0;
    lasty = size / 2;

    for (int n = 2; n <= size * size; n++)
    {
    if (values[lastx, lasty] % size == 0)
    {
    lastx = (lastx + 1) % size;
    values[lastx, lasty] = n;
    }
    else
    {
    lastx = (size + lastx - 1) % size;
    lasty = (lasty + 1) % size;
    values[lastx, lasty] = n;
    }

    }
    }

    }

    4n阶幻方的实现类:

        public class MagicSquare4n : MagicSquare
    {

    public MagicSquare4n(int size)
    : base(size)
    {

    }

    protected override void CreateMagicSquare()
    {

    values = new int[size, size];

    int n = 1;
    for (int x = 0; x < size; x++)
    {
    for (int y = 0; y < size; y++)
    {
    values[x, y] = n;
    n++;
    }

    }


    /*
    将左上区域i+j为偶数的与幻方内以中心点为对称点的右下角对角数字进行交换;
    将右上区域i+j为奇数的与幻方内以中心点为对称点的左下角对角数字进行交换。(保证不同时为奇或偶即可。)
    */

    for (int x = 0; x < size / 2; x++)
    {
    for (int y = 0; y < size / 2; y++)
    {
    if((x+y)%2==0)
    swap(ref values[x, y], ref values[size - 1 - x, size - 1 - y]);
    }

    }


    for (int x = 0; x < size / 2; x++)
    {
    for (int y = size / 2; y < size ; y++)
    {
    if ((x + y) % 2 == 1)
    swap(ref values[x, y], ref values[size - 1 - x, size - 1 - y]);
    }

    }




    }

    private void swap(ref int a, ref int b)
    {
    int temp;
    temp = a;
    a = b;
    b = temp;
    }

    }

    4n+2阶幻方的实现类:

        public class MagicSquare4n2 : MagicSquare
    {

    public MagicSquare4n2(int size)
    : base(size)
    {

    }


    protected override void CreateMagicSquare()
    {
    values = new int[size, size];


    //单偶阶幻方(斯特雷奇Ralph Strachey法)
    //n为偶数,且不能被4整除 (n=6,10,14,18,22……) (n=4k+2,k=1,2,3,4,5……)
    //(1) 把方阵分为A,B,C,D四个象限,这样每一个象限肯定是奇数阶。用楼梯法,依次在A象限,D象限,B象限,C象限按奇数阶幻方的填法填数。
    //(2)在A象限的中间行、中间格开始,按自左向右的方向,标出k格。A象限的其它行则标出最左边的k格。将这些格,和C象限相对位置上的数,互换位置。
    //(3)在B象限任一行的中间格,自右向左,标出k-1列。(注:6阶幻方由于k-1=0,所以不用再作B、D象限的数据交换), 将B象限标出的这些数,和D象限相对位置上的数进行交换,就形成幻方。

    int[,] A = new MagicSquare2n1(size / 2).GetValueArray();
    int[,] B = new MagicSquare2n1(size / 2).GetValueArray();
    int[,] C = new MagicSquare2n1(size / 2).GetValueArray();
    int[,] D = new MagicSquare2n1(size / 2).GetValueArray();

    for (int x = 0; x < size / 2; x++)
    {
    for (int y = 0; y < size / 2; y++)
    {
    B[x, y] += 2 * (size / 2) * (size / 2);//第3大
    C[x, y] += 3 * (size / 2) * (size / 2);//最大
    D[x, y] += (size / 2) * (size / 2);//第2大

    }

    }


    int k = (size - 2) / 4;

    for (int y = size / 4; y < size / 4 + k; y++)
    {
    swap(ref A[size/4,y],ref C[size/4,y]);
    }


    for (int x = 0; x < size / 2 ; x++)
    {
    if (x == size / 4) continue;
    for (int y = 0; y < k; y++)
    {

    swap(ref A[x, y], ref C[x, y]);
    }
    }


    for (int y = size / 4,count =0; count< (k-1); y--,count++)
    {
    for (int x = 0; x < size / 2; x++)
    {
    swap(ref B[x, y], ref D[x, y]);
    }
    }


    for (int x = 0; x < size; x++)
    {
    for (int y = 0; y < size; y++)
    {
    if(x<size/2 && y< size/2)
    {
    values[x, y] = A[x, y];
    }
    else if (x < size / 2 && y >= size / 2)
    {
    values[x, y] = B[x, y - size / 2];
    }
    else if (x >= size / 2 && y >= size / 2)
    {
    values[x, y] = D[x - size / 2, y - size / 2];
    }
    else
    {
    values[x, y] = C[x - size / 2, y];
    }

    }

    }


    }

    private void swap(ref int a, ref int b)
    {
    int temp;
    temp = a;
    a = b;
    b = temp;
    }

    }


    调用的时候请这样使用:

    MagicSquare ms = MagicSquareFactory.GetMagicSquare(10);
    textBox1.Text = ms.GetValueString();/*幻方字符串*/
    MessageBox.Show(ms.GetCheckString()); /*校验字符串*/

    以上就是整个实现了 代码的运行效率还是挺低的 只是做了最基本的实现 没有考虑到效率方面的事情


  • 相关阅读:
    问题描述:判断一个整数 n 是否为 2 的幂次方
    C#的关键字Explicit 和 Implicit
    .NET写入文件操作
    C# Main函数详解
    SpringBoot增加过滤XSS脚本攻击
    Hutool工具包导出Excel文件异常 You need to add dependency of poi-ooxml to your project
    微信H5表单点击输入框提示防欺诈盗号,请勿支付或输入qq密码
    RedisTemplate执行lua脚本在Redis集群模式下报错EvalSha is not supported in cluster environment.
    SpringBoot使用RedisTemplate+Lua脚本实现Redis分布式锁
    SpringBoot使用Thymeleaf打成jar包部署找不到页面
  • 原文地址:https://www.cnblogs.com/happycat1988/p/2305376.html
Copyright © 2011-2022 走看看