看到以前学校的大佬写的代码,真心觉得很nb,本蒟蒻稍微加了亿点注释,方便大家看得懂。
第一次发博客排版不怎么样,各位佬别在意
题目描述
Apple最近迷上了做幻方,Apple还是个中高手,只要你说个奇数N就能把N*N的幻方做出来。其实你可以比他做得更好的。Apple总是画得很乱,而你可以利用程序排得很整齐^_^ 幻方的要求:每一行,每一列,还有两条斜线上数字的和都相等.
输入
每行一个奇数N(0< N < 30),输入0结束
输出
输入一个奇数,输出一个幻方,顺序参照样板输出;同一列的数右对齐,数与数用一个空格分开;输出完以后加一个回车。
样例输入
5 1 0
样例输出
11 18 25 2 9 10 12 19 21 3 4 6 13 20 22 23 5 7 14 16 17 24 1 8 15 1
// 解奇阶幻方的通用模块
/* 奇数阶幻方
最经典的填法是罗伯特法(楼梯法),填写方法是这样:
把1(或最小的数)放在第一行正中;按以下规律排列剩下的n×n-1个数:
(1)每一个数放在前一个数的右上一格;
(2)如果这个数所要放的格已经超出了顶行那么就把它放在底行,
仍然要放在右一列;
(3)如果这个数所要放的格已经超出了最右列那么就把它放在最左列,
仍然要放在上一行;
(4)如果这个数所要放的格已经超出了顶行且超出了最右列,
那么就把它放在前一个数的下一行同一列的格内;
(5)如果这个数所要放的格已经有数填入,处理方法同(4)。
这种写法总是先向“右上”的方向,象是在爬楼梯。
三阶幻方:
8 1 6
3 5 7
4 9 2 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int sort(int n);
int main()
{
int n;
while (scanf("%d", &n), n != 0)
sort(n); // n 为阶数
return 0;
}
int sort(int n)
{
int i, x = 0, y = 0, j;
int(*a)[n] = (int(*)[n])malloc(sizeof(int) * n * n); // 申请动态二维数组 在这里也可以 a[n][n](直到 C99 才支持)
x = n / 2; // 指向中间列
y = 0;
for (i = 1; i <= n * n; i++)
{
a[y][x] = i; // 把 1 (或最小的数)放在第一行正中
if (i % n == 0) // 每放 n 个后,下一个一定是已经填过的格子
y++; // 需要在下一行继续放
else
x++, y--; // 向右上方移动
x = x % n; // 当 x 在最右方还需要右移的时候,把 x初始化为 1
y = (y % n + n) % n; // 当 y 在最上方,且还需要向右上移动时,y--后 y = -1,需要把 y 变为n - 1, 当 y 在最下方时还需要向下移时, 作用等同于 y = y % n
}
int fmt = log10(n * n); // 取位数, 按照要求输出,数字之间留出空格
if (fmt == 0) // fmt -> format 由于30*30 = 900最大为3位数,故下面只列举了3种情况
{
for (i = n - 1; i >= 0; i--) // 题目格式刚好上下反转了一下
{
for (j = 0; j < n - 1; j++) // 左右并没有反转
{
printf("%d ", a[i][j]);
}
printf("%d", a[i][n - 1]); // 每行最后一个不输出空格
printf("\n");
}
}
else if (fmt == 1)
{
for (i = n - 1; i >= 0; i--)
{
for (j = 0; j < n - 1; j++)
{
printf("%2d ", a[i][j]);
}
printf("%2d", a[i][n - 1]);
printf("\n");
}
}
else if (fmt == 2)
{
for (i = n - 1; i >= 0; i--)
{
for (j = 0; j < n - 1; j++)
{
printf("%3d ", a[i][j]);
}
printf("%3d", a[i][n - 1]);
printf("\n");
}
}
free(a); // 申请的空间用后释放 如果上方用的是a[n][n],就不用写 free了(如果写了程序会异常结束)
printf("\n"); // 按照题目要求,每组数据直接要有一个换行符隔开
return 0;
}