蓝桥杯 9. 九宫幻方

九宫幻方

原题目链接

题目描述

小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分。

三阶幻方 是指将 1 ~ 9 不重复地填入一个 3×3 的矩阵中,使得每一行、每一列和每一条对角线的和都是相同的。

三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:

"二四为肩,六八为足,左三右七,戴九履一,五居其中"

通过这句口诀,可以构造出一个标准九宫格,如下:

in 复制代码
4 9 2  
3 5 7  
8 1 6  

有意思的是,所有的三阶幻方 ,都可以通过这个标准九宫格进行若干次镜像和旋转操作之后得到。


任务

现在小明将一个三阶幻方(不一定是标准形)中的一些数抹掉,交给邻居家的小朋友来进行还原,并希望她判断是否只有唯一解

你也被小明交付了同样的任务------写一个程序完成这个判断。


输入描述

输入仅包含一组测试数据,为一个 3×3 的矩阵。矩阵中的数为 0 表示该位置的数被抹掉。

保证输入的矩阵至少可以还原出一组可行的三阶幻方。


输出描述

  • 如果仅能还原出一组可行的三阶幻方,则将该幻方输出,按矩阵形式每行一个空格分隔的整数。
  • 否则,输出 "Too Many"(不含引号)。

输入样例

in 复制代码
0 7 2
0 5 0
0 3 0

输出样例

out 复制代码
6 7 2
1 5 9
8 3 4

c++代码

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

vector<vector<int>> arr(3, vector<int>(3)), ans;
vector<bool> know(10, true);
int cont = 0, sum = 0;

void dfs(int i, int j) {
    if (cont >= 2 || i < 0 || i > 3 || j < 0 || j >= 3) return;
    if (i == 3) {
        sum = arr[0][0] + arr[1][1] + arr[2][2];
        if (sum != arr[0][2] + arr[1][1] + arr[2][0]) return;
        for (int i = 0; i < 3; i++) {
            int mid = 0;
            for (int j = 0; j < 3; j++) mid += arr[i][j];
            if (mid != sum) return;
        }
        for (int j = 0; j < 3; j++) {
            int mid = 0;
            for (int i = 0; i < 3; i++) mid += arr[i][j];
            if (mid != sum) return;
        }
        cont++;
        ans = arr;
        return;
    }
    int x, y;
    if (j == 2) x = i + 1, y = 0;
    else x = i, y = j + 1;
    if (arr[i][j] != 0) dfs(x, y);
    else {
        for (int k = 1; k <= 9; k++) {
            if (!know[k]) continue;
            know[k] = false;
            arr[i][j] = k;
            dfs(x, y);
            arr[i][j] = 0;
            know[k] = true;
        }
    }
}

int main() {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            cin >> arr[i][j];
            if (arr[i][j] != 0) know[arr[i][j]] = false;
        }
    }
    dfs(0, 0);
    if (cont == 1) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (j == 2 && i != 2) cout << ans[i][j] << endl;
                else cout << ans[i][j] << " ";
            }
        }
    }
    else cout << "Too Many";
    return 0;
}//by wqs

思路解析

每个数字只能出现一次,要记录哪些数字被选择了,我们只能选择没有被选择的数字。

cpp 复制代码
if (arr[i][j] != 0) know[arr[i][j]] = false;

暴力枚举每个格子可能的数字就行。

cpp 复制代码
for (int k = 1; k <= 9; k++) {
    if (!know[k]) continue;
    know[k] = false;
    arr[i][j] = k;
    dfs(x, y);
    arr[i][j] = 0;
    know[k] = true;
}

枚举完之后判断是否满足每一行、每一列和每一条对角线的和都是相同的。

cpp 复制代码
sum = arr[0][0] + arr[1][1] + arr[2][2];
if (sum != arr[0][2] + arr[1][1] + arr[2][0]) return;
for (int i = 0; i < 3; i++) {
    int mid = 0;
    for (int j = 0; j < 3; j++) mid += arr[i][j];
    if (mid != sum) return;
}
for (int j = 0; j < 3; j++) {
    int mid = 0;
    for (int i = 0; i < 3; i++) mid += arr[i][j];
    if (mid != sum) return;
}

记录符合条件的数目,如果大于2直接跳出dfs函数,防止超时。

cpp 复制代码
if (cont >= 2 || i < 0 || i > 3 || j < 0 || j >= 3) return;
相关推荐
凌康ACG8 分钟前
易语言使用OCR
c++·yolo·c#·ocr·易语言
范纹杉想快点毕业33 分钟前
C++多重继承详解与实战解析
开发语言·c++
太空1号2 小时前
飞腾D2000,麒麟系统V10,docker,ubuntu1804,小白入门喂饭级教程
linux·c++·docker
Matlab仿真实验室2 小时前
基于Matlab实现LDA算法
开发语言·算法·matlab
@蓝莓果粒茶2 小时前
LeetCode第244题_最短单词距离II
c++·笔记·学习·算法·leetcode·职场和发展·c#
多多*2 小时前
蓝桥杯国赛训练 day1
java·开发语言·数据库·redis·缓存·职场和发展·蓝桥杯
iCxhust3 小时前
Deepseek给出的8255显示例程
c语言·开发语言·c++·单片机·嵌入式硬件
宋一诺333 小时前
机器学习——随机森林算法
算法·随机森林·机器学习
无聊的小坏坏3 小时前
二分查找的边界艺术:LeetCode 34 题深度解析
算法·leetcode
CHNLee玉米3 小时前
题目解析 1.找单独的数 | 豆包MarsCode AI刷题
算法