洛谷P2615 [NOIP2015 提高组] 神奇的幻方]

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本文主要是介绍洛谷P2615 [NOIP2015 提高组] 神奇的幻方的解法。思路是参考大佬LesterYu。蒟蒻的哭泣 。看大佬代码琢磨了一个小时,终于弄懂了,欣喜若狂,就说说我对大佬LesterYU美丽的公式。

x=(x-2+n)%n+1;
y=y%n+1;

下面请欣赏美丽的幻方

一题目描述&&思路

P2615 [NOIP2015 提高组] 神奇的幻方

幻方是一种很神奇的 N∗N 矩阵:它由数字1,2,3,⋯⋯,N×N 构成,且每行、每列及两条对角线上的数字之和都相同。

当 N 为奇数时,我们可以通过下方法构建一个幻方:

首先将 1 写在第一行的中间。

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

若 (K-1)(K−1) 在第一行但不在最后一列,则将 KK 填在最后一行, (K-1)(K−1) 所在列的右一列;
若 (K-1)(K−1) 在最后一列但不在第一行,则将 KK 填在第一列, (K-1)(K−1) 所在行的上一行;
若 (K-1)(K−1) 在第一行最后一列,则将 KK 填在 (K-1)(K−1) 的正下方;
若 (K-1)(K−1) 既不在第一行,也不在最后一列,如果 (K-1)(K−1) 的右上方还未填数,则将 KK 填在 (K-1)(K−1) 的右上方,否则将 KK 填在 (K-1)(K−1) 的正下方。
现给定 N ,请按上述方法构造N×N 的幻方。

思路:通过分析构造奇数阶幻方的条件,我们可以知道从第一行中间开始,
之后若上一个数右上角没有数则把数放在上面,若有数则放在上一个数的下面。
1.根据题目在(1,2)填1

行/列123
11
2
3

2.填完1后看1的"右上角"即(3,3),没数,填2

行/列123
11
2
32

3.填完2后看2的"右上角"即(2,1),没数,填3

行/列123
11
23
32

4.填完3后看3的"右上角"即(1,2),有数,填4在(3,1)

行/列123
11
23
342

5.填完4后看4的"右上角"即(2,2),没数,填5

行/列123
11
235
342

6.填完5后看5的"右上角"即(1,3),没数,填6

行/列123
116
235
342

7.填完6后看6的"右上角"即(1,3),有数,填7在(2,3)

行/列123
116
2357
342

8.填完7后看7的"右上角"即(1,1),没数,填8在(1,1)

行/列123
1816
2357
342

8.填完8后看8的"右上角"即(3,2),没数,填9在(3,2)

行/列123
1816
2357
3492

二、代码实现

#include <stdio.h>

int main() {
	int n;
	scanf("%d", &n);

	int a[40][40] = {0};
	int x = 1, y = (n + 1) / 2; //x,y代表幻方的行和列
	//创建幻方
	for (int i = 1; i <= n * n; ++i) {
		a[x][y] = i;

		if (!a[(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) {
			printf("%d ", a[i][j]);
		}
		printf("\n");
	}

}

下面对幻方创建中关键代码分析

if (!a[(x - 2 + n) % n + 1][y  % n + 1]) {
			x = (x - 2 + n) % n + 1;
			y = y % n + 1;
		} else {
			x = x % n + 1;
		}

上面的代码即实现判断右上角有没有数,无则填在右上角,有则填在正下方

我们知道a[n1][n2],n1代表行,n2代表列.
但为什么用(x - 2 + n) % n + 1和y % n + 1来表示呢?
我们想右上角不就是在上一行在右一列吗。
我们先看行的表达式。
上一行?简单。x-1,不就行了吗?可惜计算机没有那么智能,x=1时,不会帮我们跳到第n行。
想啊想。哎,再加一个n不就行了吗!这样x-1+n就可以实现从第一行跳到n行了。
仔细想想,好像其他行又不行了。x=2,3,4…时,得到的行大于n行了。
聪明的一休绕绕头。哎,我们有%。我们%n就可以了。(x-1+n)%n
我们又又又发现>1行的是可以了,但x=1时又失败了。
😫要疯啦!!!
卡了半个小时,我又滚去观摩大佬的原式了。
最后仿照式子,想出一个"+1-1"的方法。
我们在(x-1+n)%n+1-1%n,(1%n==1)
整理一下就是(x-2+n)%n+1了。👍。
或者把x-1+n写成x-2+n+1这样更加自然点。
列的表示比较简单,这里就不再展开了。

总结

今天又是蒟蒻的一天。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值