幻方的生成

幻方,有时又称魔方(该称呼现一般指立方体的魔术方块)或纵横图,由一组排放在正方形中的整数组成,其每行、每列以及两条对角线上的数之和均相等。通常幻方由从1N^2的连续整数组成,其中N为正方形的行或列的数目。因此N阶幻方有NN列,并且所填充的数为从1N^2

幻方可以使用N阶方阵来表示,方阵的每行、每列以及两条对角线的和都等于常数M_2(N),如果填充数为1,2,\dots,N^2,那么有

M_2(N) = \frac{N(N^2+1)}{2}

根据幻方阶数的不同,产生幻方的方法也不区别

一般可以分为下了三种情况:

  1. 奇数阶幻方
  2. 4M阶幻方
  3. 4M+2阶幻方

奇数阶幻方构造法 

Siamese方法是构造奇数阶幻方的一种方法,说明如下:

  • 1放置在第一行的中间。
  • 顺序将2,3,\dots等数放在右上方格中。
  • 当右上方格出界的时候,则由另一边进入。
  • 当右上方格中已经填有数,则把数填入正下方的方格中。
  • 按照以上步骤直到填写完所有N^2个方格。

(由于幻方的对称性,也可以把右上改为右下、左上以及左下等方位)

\begin{bmatrix}8 & 1 & 6 \\3 & 5 & 7 \\4 & 9 & 2 \\\end{bmatrix}

偶数阶幻方构造法

4M阶的情况

将4M阶分成M*M个4*4的块,每块里面值改变对角线和负对角线上的数字,将对角线上的数字a_(ij) 变成(n^2+1)-a_(ij)

MagicSquareDoublyEven

4M+2阶的情况

这个情况的构造情况比较麻烦

详见http://blog.sina.com.cn/s/blog_639b95e90100i6h4.html


下面附上求n阶幻方的代码,n为以上三种情况

#include <stdio.h>
#include <string.h>

const int N = 101;
int n;

int magic[N][N];

void Swap(int &a, int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

void PrintMagic(int n)
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
			printf("%d ", magic[i][j]);
		printf("\n");
	}
}

void CreateOddMagic(int n, int si = 0, int sj = 0, int add = 0)
{
	int i, j;
	for (i = 0; i < n; i++)
		for (j = 0; j < n; j++)
			magic[si+i][sj+j] = 0;
	i = 0;
	j = n / 2;
	magic[si+i][sj+j] = 1 + add;
	int inc = 2;
	while (inc <= n * n)
	{
		int ni = i - 1;int nj = j + 1;
		if ((ni == -1 && nj == n) || (ni >= 0 && ni < n && nj >= 0 && nj < n && magic[si+ni][sj+nj]))
		{
			ni = i + 1;
			nj = j;
		}
		else if (ni == -1)
		{
			ni = n - 1;
		}
		else if (nj >= n)
		{
			nj = 0;
		}
		magic[si+ni][sj+nj] = add + inc++;
		i = ni;
		j = nj;
	}
	//PrintMagic(n);
}

void Create4(int si, int sj, int n)
{
	int i;
	int j;
	for (i = 0; i < 4; i++)
	{
		for (j = 0; j < 4; j++)
		{
			if (i == j || i == 3 - j)
			{
				magic[si+i][sj+j] = n * n + 1 - magic[si+i][sj+j];
			}
		}
	}
}

void Create4Magic(int n)
{
	int i;
	int j;
	for (i = 0; i < n; i++)
		for (j = 0; j < n; j++)
			magic[i][j] = i * n + j + 1;
	for (i = 0; i < n; i += 4)
	{
		for (j = 0; j < n; j += 4)
		{
			Create4(i, j, n);
		}
	}
}

void Create4M2Magic(int n)
{
	int m = (n - 2) / 4;
	int i;
	int j;
	memset(magic, 0, sizeof(magic));
	int add = n * n / 4;
	CreateOddMagic(n/2, 0, 0, 0);
	CreateOddMagic(n/2, 0, n/2, 2* add);
	CreateOddMagic(n/2, n/2, 0, 3 * add);
	CreateOddMagic(n/2, n/2, n/2, add);
	for (i = 0; i < n/2; i++)
	{
		for (j = 0; j < m - 1; j++)
		{
			Swap(magic[i][j], magic[i+n/2][j]);
		}
		if (i != m)
			Swap(magic[i][j], magic[i+n/2][j]);
		else
			Swap(magic[i][m], magic[i+n/2][m]);
	}
	for (i = 0; i < n/2; i++)
	{
		for (j = n - m + 1; j < n; j++)
			Swap(magic[i][j], magic[n/2+i][j]);
	}
}

int main(void)
{
	while (scanf("%d", &n) && n)
	{
		if (n % 2 == 1)
		{
			CreateOddMagic(n);
		}
		else if (n % 4 == 0)
		{
			Create4Magic(n);
		}
		else
		{
			Create4M2Magic(n);
		}
		PrintMagic(n);
	}

	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值