幻方问题

问题描述

幻方是一种很神奇的 N*NN∗N 矩阵:它由数字 1,2,3,⋯⋯,N×N 构成,且每行、每列及两条对角线上的数字之和都相同。
当 N 为奇数时,我们可以通过下方法构建一个幻方:
首先将 1写在第一行的中间。

之后,按如下方式从小到大依次填写每个数 K(K=2,3,⋯,N×N) :

  1. 若 (K-1)在第一行但不在最后一列,则将 K 填在最后一行, (K-1)所在列的右列;
  2. 若 (K-1)在最后一列但不在第一行,则将 K填在第一列, (K-1)所在行的上3一行;
  3. 若 (K-1)在第一行最后一列,则将 K填在 (K-1)的正下方;
  4. 若 (K-1)既不在第一行,也不在最后一列,如果 (K-1) 的右上方还未填数,则将 KK 填在 (K-1) 的右上方,否则将 K 填在 (K-1) 的正下方。

现给定 N ,请按上述方法构造 N×N 的幻方。

输入格式

一个正整数 N ,即幻方的大小。

输出格式

共 N行 ,每行 N个整数,即按上述方法构造出的 N×N 的幻方,相邻两个整数之间用单空格隔开。

当时看到这一题,稍微有点傻。因为这题就是一个模拟题,而且整个的模拟过程都已经告诉你了。但却属于普及题而非入门题,比较奇怪。但是该题暗藏玄机。

首先是直接模拟的代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long int ll;

ll magic_square[40][40];
ll x[1600];
ll y[1600];

int main()
{
	int N; cin >> N;
	magic_square[1][N / 2 + 1] = 1;
	x[1] = 1; y[1] = N / 2 + 1;
	for (int i = 2; i <= N * N; i++)
	{
		if (x[i - 1] == 1 && y[i - 1] != N) 
		{
			magic_square[N][y[i - 1] + 1] = i;
			x[i] = N; y[i] = y[i - 1] + 1;
		}
		else if (x[i - 1] != 1 && y[i - 1] == N) 
		{
			magic_square[x[i - 1] - 1][1] = i;
			x[i] = x[i - 1] - 1;
			y[i] = 1;
		}
		else if (magic_square[1][N]==i-1)
		{
			magic_square[2][N] = i;
			x[i] = 2;
			y[i] = N;
		}
		else if (x[i - 1] != 1 && y[i - 1] != N)
		{
			if (magic_square[x[i - 1] - 1][y[i - 1] + 1] == 0)
			{
				magic_square[x[i - 1] - 1][y[i - 1] + 1] = i;
				x[i] = x[i - 1] - 1; y[i] = y[i - 1] + 1;
			}
			else
			{
				magic_square[x[i - 1] + 1][y[i - 1]] = i;
				x[i] = x[i - 1] + 1; y[i] = y[i - 1];
			}
		}
	}
	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= N; j++)
		{
			cout << magic_square[i][j] << ' ';
		}
		cout << endl;
	}

	return 0;

}

十分简单粗暴

但这一题还有更简便的解法。可以将题目分析一遍。以3阶幻方为例
在这里插入图片描述
从1开始,将剩余的数按一下次序放:

1. 如果“右上角”有数,则置于其正下方
2. 如果“右上角”没有数,则置于其右上角

此处的“右上角”并非真正意义上的右上角,1位于第一行正中间,而第一行上面没有行数,则放于最后一行,即所谓“上行”一行,而后右行一列,即到达所谓右上角,将2放于最后一行,最后一列。
2的右方没有列,故放于第一列,再上行一行,将3置于第二行,第一列。

简单来说:将整个幻方矩阵的每一个空位视为循环的

这样一来就可以很大程度上简化代码

#include <iostream>
using namespace std;

int n, ms[40][40], x, y;

int main() {
	cin >> n;
	x = 1, y = (n + 1) / 2;
	for (int i = 1; i <= n * n; i++) {
		ms[x][y] = i;
		if (!ms[(x - 2 + n) % n + 1][y % n + 1]) 
			x = (x - 2 + n) % n + 1, y = y % n + 1;
		else x = x % n + 1;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			cout << ms[i][j] << ' ';
		}
		cout << endl;
	}
}

运行结果

在这里插入图片描述

在这里插入图片描述

  • 10
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值