蓝桥杯 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;
相关推荐
宁静致远202131 分钟前
【C++设计模式】第五篇:装饰器模式
c++·设计模式·装饰器模式
青草地溪水旁1 小时前
Linux 高性能 I/O 事件通知机制的核心系统调用—— `epoll_ctl`
linux·c语言·c++
孙同学_1 小时前
【C++】AVL树
c++·redis
靠近彗星1 小时前
2.1线性表
数据结构
island13141 小时前
【Redis#9】其他数据结构
数据结构·数据库·redis
行走的bug...1 小时前
用图论来解决问题
算法·图论
君宝1 小时前
Linux ALSA架构:PCM_OPEN流程 (二)
java·linux·c++
island13142 小时前
【C++框架#5】Elasticsearch 安装和使用
开发语言·c++·elasticsearch
nsjqj2 小时前
数据结构:优先级队列(堆)
数据结构
岁忧3 小时前
(LeetCode 每日一题) 3541. 找到频率最高的元音和辅音 (哈希表)
java·c++·算法·leetcode·go·散列表