魔方阵(幻方)构造方法

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()); /*校验字符串*/

 

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


posted @ 2011-12-28 21:08  happycat1988  阅读(3544)  评论(0编辑  收藏  举报