1 条题解

  • 0
    @ 2025-5-12 19:40:44

    以下是对给定代码的题解,包括问题分析、算法思路、代码实现细节以及复杂度分析:

    问题分析

    1. 给定一个由 52 个字母(小写 'a' 到 'z' 和大写 'A' 到 'Z')组成的集合 (S)。
    2. 存在 (m) 个推导关系,形式为 (S1 => S2),表示从声明集合 (S1) 可以推导出声明集合 (S2)。
    3. 有 (n) 个查询,每个查询给出一个声明集合 (Q),需要根据推导关系找出从 (Q) 能推导出的所有声明。

    复杂度分析

    时间复杂度: - 对于每个查询,遍历 (n) 个推导关系,并且在最坏情况下,每次遍历推导关系时可能需要检查每个推导关系的前提声明集合和可推导出的声明集合。假设每个声明集合的长度为 (L),则时间复杂度为 (O(n \times L \times m)),其中 (n) 是推导关系的数量,(m) 是查询的数量,(L) 是声明集合的长度。

    代码注释

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <cstring> 
    using namespace std;
    
    // 定义结构体存储推导关系,a为前提声明集合,b为可推导出的声明集合
    struct nod{
        string a;
        string b;
    }da[1010];
    int vis[1010]; // 标记推导关系是否已处理
    int hs[510]; // 标记当前已知的声明
    
    int main() 
    {
        int n, m;
        while(scanf("%d%d", &n, &m) != EOF) {
            // 读取n个推导关系
            for(int i = 0; i < n; i++) {
                char ta[200];
                char tb[200];
                // 读取推导关系,格式为 %s => %s
                scanf("%s => %s", ta, tb);
                da[i].a = ta;
                da[i].b = tb;
            }
            // 处理m个查询
            for(int i = 0; i < m; i++) {
                char tc[200];
                scanf("%s", tc);
                string c = tc;
                memset(vis, 0, sizeof(vis)); // 初始化推导关系标记数组
                memset(hs, 0, sizeof(hs)); // 初始化声明标记数组
    
                // 标记查询中的声明
                for(int j = 0; j < c.size(); j++) {
                    hs[c[j]] = 1;
                }
    
                int ff = 1;
                // 循环处理推导关系,直到没有新的声明可推导
                while(ff) {
                    ff = 0;
                    for(int j = 0; j < n; j++) {
                        if(vis[j] == 0) {
                            int flag = 0;
                            // 检查推导关系的前提声明集合
                            for(int k = 0; k < da[j].a.size(); k++) {
                                if(hs[da[j].a[k]] != 1) {
                                    flag = 1;
                                    break;
                                }
                            }
                            // 如果前提声明集合中的声明都已标记,则处理该推导关系
                            if(flag == 0) {
                                ff = 1;
                                vis[j] = 1;
                                // 标记可推导出的声明集合中的声明
                                for(int k = 0; k < da[j].b.size(); k++) {
                                    hs[da[j].b[k]] = 1;
                                }
                            }
                        }
                    }
                }
    
                // 按小写字母顺序输出已标记的声明
                for(int i = 'a'; i <= 'z'; i++) {
                    if(hs[i] == 1) {
                        cout << (char)i;
                    }
                }
                // 按大写字母顺序输出已标记的声明
                for(int i = 'A'; i <= 'Z'; i++) {
                    if(hs[i] == 1) {
                        cout << (char)i;
                    }
                }
                cout << endl;
            }
        }
        return 0;
    }
    
    • 1

    信息

    ID
    629
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者