📜  门| GATE-CS-2005 |第 90 题(1)

📅  最后修改于: 2023-12-03 15:28:42.546000             🧑  作者: Mango

门 | GATE-CS-2005 |第 90 题

这是一道 GATE 计算机科学考试的题目,需要对程序员进行一定的挑战才能完成。

题目描述

在一个 n x n 的方形表格中填入 1~n 的数,要求填成一个 n 阶幻方,即每行、每列和对角线上的数字加起来都相等。

给定整数 n (3≤n≤100)。请编写一个程序,以填出所有合法的 n 阶幻方。

输入格式

一个整数 n。

输出格式

所有合法的 n 阶幻方,每个幻方需用每行数字以空格隔开,行末无空格。

程序示例

下面是一个可能的输出示例:

1 15 14 4
12 6 7 9
8 10 11 5
13 3 2 16

1 12 15 8 57 56 29 36
14 7 6 9 54 59 34 27
19 23 24 20 43 40 47 51
32 30 25 18 41 46 53 55
37 42 39 44 26 17 22 31
52 50 45 38 21 28 33 35
49 41 38 43 22 11 14 31
40 34 29 20 60 51 54 47
解题思路

本题需要使用回溯法进行求解,具体思路如下:

  1. 将幻方的第一行进行初始化,以保证每行的和相等。

  2. 对于幻方中每一个位置,从 1 开始尝试填入数字,每填入一个数字,在判断该行或该列与斜线的和是否相等。

  3. 如果全部位置都已填写,则输出该幻方。

  4. 如果当前填写的数字已经大于 n,则回退到上一个位置尝试其他数字。

  5. 如果所有数字都尝试了,都不能满足要求,则回退到上一个位置尝试其他数字。如果回退时回到了第一列,则说明幻方填写失败。

下面是 Python 代码片段:

# 初始化幻方的第一行,sum_list 是每行每列和的列表
def init_square(square_size):
    square = [[0] * square_size for i in range(square_size)]
    square[0][square_size//2] = 1
    i, j = 0, square_size//2
    for n in range(2, square_size**2+1):
        i -= 1
        j += 1
        if i < 0 and j < square_size:
            i = square_size - 1
        elif j == square_size and i >= 0:
            j = 0
        elif i < 0 and j == square_size:
            i, j = 0, square_size - 2
        if square[i][j] != 0:
            i += 1
            j -= 2
        square[i][j] = n
    return square

# 回溯求解幻方
def magic_square(square_size):
    square = [[0] * square_size for i in range(square_size)]
    sum_list = [0] * (square_size * 2 + 2)
    square[0][square_size//2] = 1
    i, j = 0, square_size//2
    while i >= 0:
        if square[i][j] == 0:
            k = 1
            while k <= square_size:
                square[i][j] = k
                if i == j:
                    sum_list[square_size] += k
                if i + j == square_size - 1:
                    sum_list[square_size+1] += k
                sum_list[i] += k
                sum_list[j+square_size] += k
                if k == square_size:
                    pass
                elif sum_list[i] > 0 and sum_list[i] > sum_list[square_size+1]:
                    k = square_size - 1
                elif sum_list[square_size] > 0 and sum_list[square_size] > sum_list[square_size+1]:
                    k = square_size - 1
                elif j == square_size-1 and sum_list[j+square_size] != sum_list[square_size]:
                    k = square_size - 1
                elif i == square_size-1 and sum_list[i] != sum_list[square_size]:
                    k = square_size - 1
                else:
                    i1 = i + 1
                    j1 = j
                    if i1 == square_size:
                        i1 = 0
                    magic_square(square_size, i1, j1, sum_list)
                sum_list[i] -= k
                sum_list[j+square_size] -= k
                if i == j:
                    sum_list[square_size] -= k
                if i + j == square_size - 1:
                    sum_list[square_size+1] -= k
                square[i][j] = 0
                k += 1
        i, j = next_position(i, j, square_size)

# 求解幻方
def next_position(i, j, n):
    if i == n-1 and j == n-1:
        return -1, -1
    if j == n-1:
        return i+1, 0
    return i, j+1