T3-加密通信题解

T3-加密通信

题目描述

在一次军事演习中,小凯担任通信兵,负责解密传来的信息。他会收到一份 nn 的数字 表(仅包含 0-9 共 10 种数码),和一份 mm 的字母表(仅包含 A-Z、a-z 共 52 种字符)。 数字表被称为解密卡,字母表被称为加密卡。规定如下名词:

  • 1.覆盖区域:将数字表和字母表对齐,使得数字表在上,字母表在下,数字与字母一一 对应,如果数字表的 1 行 1 列对应字母表的 x 行 y 列,那么数字表的 1+k 行 1+k 列对应字母 表的 x+k 行 y+k 列,此时覆盖区域为字母表以 x 行 y 列为左上角、x+n-1 行 y+n-1 列为右下角 的正方形范围。简单来说,根据图片显示,若数字表的左上角盖在了 2 行 2 列的位置,则数 字表会覆盖(2,2)到(3,3)这片区域。
  • 2.有效区域:称某字母和其在字母表的顺序数字为互相对应,字母 A 和 a 是第 1 个字母、 字母 I 和 i 是第 9 个字母,那么 A、a 和 1 对应,I、i 和 9 对应,以此类推。如果覆盖区域 的四个顶点字母恰好和原始数字表的四个顶点数字互相对应,那么这个覆盖区域称之为有效区域。
  • 3.数字关联:0 和任何字母关联,1 不能和任何字母关联,2-9 中的质数和大写字母关联, 2-9 中的合数和小写字母关联。若关联成功,则提取出来作为密码的一部分,如上图中 2 是 质数,需关联大写字母,2 对应的是 B,关联成功;3 是质数,需关联大写字母,3 对应的 c 关联失败;4 是合数,需关联小写字母,而 4 对应的是 D,关联失败。因此上述图中,本次 覆盖只关联成功一次,提取出一个密码 B。
    1. 解密数字表:大小为 n*n,可以由原始数字表顺时针旋转若干次 90°得到。
  • 5.区域解密:有效区域和解密数字表对齐,从左到右从上到下,将和解密数字表中对应 位置数字恰好关联的字母提取出来,构成字符串。
    一次解密操作包含以下步骤:首先从左到右从上到下找出所有有效区域,依次进行解密。 对于每个有效区域首先用原始数字表进行 1 次区域解密,然后根据当前有效区域的顶点大写 字母数量 x,额外进行 x 次区域解密(如图示中四个顶点有两个大写字母,因此需旋转两次), 第 i 次解密时将原始数字表顺时针旋转 i*90°后作为解密数字表再进行区域解密。最后将所 有区域解密的字符串按序连接,构成最终的解密字符串。 你需要帮助小凯完成解密工作。

输入格式

共 n+m+1 行, 第 1 行两个正整数 n 和 m,分别代表数字表和字母表的大小; 第 2 至 n+1 行分别有连续的 n 个数码字符,代表数字表的内容; 第 n+2 至 n+m+1 行分别有连续的 m 个字母字符,代表字母表的内容。

输出格式

仅一行一个字符串,代表解密后的答案。如果答案为空串,你需要输出"No solution"

样例 #1

样例输入 #1

2 3  
11  
13  
AAB  
ACB  
BzB

样例输出 #1

CAAAC

样例 #2

样例输入 #2

3 4  
101  
245  
313  
DABa  
AFab  
Fcdc  
cdcD

样例输出 #2

BFaABabFFcAFcd

提示

  • 对于 30%的数据,保证输入的 m<=10。 在前 30%中有 10%的数据,保证数字表中仅含有 0 和 1。
  • 对于 70%的数据,保证输入的 m<=50。 在前 70%中有 30%的数据,保证字母表中仅含有小写字母。
  • 对于 100%的数据,保证输入的 n<=m<=80。

解析

解题思路如下:

  1. 首先读入数字表和字母表的大小n和m,然后读入nn的数字表和mm的字母表。

  2. 从字母表的左上角开始,枚举所有可能的n*n的覆盖区域,对于每个覆盖区域:

    a. 判断该覆盖区域是否为有效区域,即四个顶点字母是否和原始数字表的四个顶点数字互相对应。如果是有效区域,记录下该区域四个顶点中大写字母的数量x。

    b. 如果是有效区域,则首先用原始数字表进行一次区域解密,然后根据x的值,将原始数字表顺时针旋转x*90度,再进行x次区域解密。

    c. 区域解密时,将解密数字表与有效区域对齐,遍历解密数字表的每个位置,如果该位置的数字与对应的字母满足数字关联关系,则将该字母提取出来。

  3. 将所有有效区域解密得到的字符串按顺序拼接,即为最终的解密字符串。如果最终字符串为空,则输出"No solution"。

下面是C++的代码实现:

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

int n, m;

// 判断覆盖区域是否为有效区域
bool validArea(const vector<vector<char>>& digit, const vector<vector<char>>& map, int& upperNums, int startI, int startJ) {
    vector<pair<int, int>> corners = {{0, 0}, {0, n - 1}, {n - 1, 0}, {n - 1, n - 1}};
    for (const auto& corner : corners) {
        int i = corner.first;
        int j = corner.second;
        if (digit[i][j] == '0') {
            continue;
        }
        if (isupper(map[startI + i][startJ + j])) upperNums++;
        char c = toupper(map[startI + i][startJ + j]);
        if ((digit[i][j] - '0') != (c - 'A' + 1)) {
            return false;
        }
    }
    return true;
}

// 顺时针旋转数字表90度
vector<vector<char>> rotateMatrix90(const vector<vector<char>>& matrix) {
    int n = matrix.size();
    vector<vector<char>> rotated(n, vector<char>(n));
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            rotated[j][n - i - 1] = matrix[i][j];
        }
    }
    return rotated;
}

// 区域解密
void decode(const vector<vector<char>>& digit, const vector<vector<char>>& map, int times, int startI, int startJ, string& ans) {
    vector<vector<char>> rotate = digit;
    while(times--) {
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                if(rotate[i][j] == '1') {
                    continue;
                } else if(rotate[i][j] == '0') {
                    ans += map[startI + i][startJ + j];
                } else if(rotate[i][j] == '2' || rotate[i][j] == '3' || rotate[i][j] == '5' || rotate[i][j] == '7') {
                    if(isupper(map[startI + i][startJ + j])) {
                        ans += map[startI + i][startJ + j];
                    }
                } else if(rotate[i][j] == '4' || rotate[i][j] == '6' || rotate[i][j] == '8' || rotate[i][j] == '9') {
                    if(islower(map[startI + i][startJ + j])){
                        ans += map[startI + i][startJ + j];
                    }
                }
            }
        }
        rotate = rotateMatrix90(rotate);
    }
}

int main() {
    cin >> n >> m;

    vector<vector<char>> digit(n, vector<char>(n));
    vector<vector<char>> map(m, vector<char>(m));

    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            cin >> digit[i][j];
        }
    }

    for(int i = 0; i < m; i++) {
        for(int j = 0; j < m; j++) {
            cin >> map[i][j];
        }
    }

    string ans;
    for(int i = 0; i < m - n + 1; i++) {
        for(int j = 0; j < m - n + 1; j++) {
            int upperNums = 0;
            if(validArea(digit, map, upperNums, i, j)) {
                decode(digit, map, upperNums + 1, i, j, ans);
            }
        }
    }

    if(ans.size() == 0){
        cout << "No solution";
        return 0;
    }
    cout << ans << endl;
    return 0;
}

该代码先判断每个覆盖区域是否为有效区域,如果是则进行解密。解密时先用原始数字表解密一次,然后根据有效区域顶点大写字母的数量确定额外需要解密的次数,每次解密前都将数字表顺时针旋转90度。最后将所有解密得到的字符串拼接输出。如果最终没有解密得到任何字符,则输出"No solution"。

相关推荐
NuyoahC4 分钟前
算法笔记(十一)——优先级队列(堆)
c++·笔记·算法·优先级队列
jk_1016 分钟前
MATLAB中decomposition函数用法
开发语言·算法·matlab
penguin_bark1 小时前
69. x 的平方根
算法
这可就有点麻烦了1 小时前
强化学习笔记之【TD3算法】
linux·笔记·算法·机器学习
苏宸啊1 小时前
顺序表及其代码实现
数据结构·算法
lin zaixi()1 小时前
贪心思想之——最大子段和问题
数据结构·算法
FindYou.1 小时前
C - Separated Lunch
算法·深度优先
夜雨翦春韭1 小时前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法
Kent_J_Truman1 小时前
【平方差 / C】
算法
一直学习永不止步1 小时前
LeetCode题练习与总结:H 指数--274
java·数据结构·算法·leetcode·数组·排序·计数排序