1 条题解

  • 0
    @ 2025-5-12 17:58:20

    问题理解

    我们需要从给定的单词列表中找到最长的链,其中每个单词是前一个单词的“混合扩展”。一个单词 A 是另一个单词 B 的“混合扩展”,如果 A 可以通过在 B 中添加一个字母并重新排列得到。例如,"ab", "bar", "crab", "cobra", 和 "carbon" 形成一个长度为 5 的链。

    解决思路

    输入处理:读取输入的单词列表。 预处理:计算每个单词的字符频率(哈希),这将帮助我们快速判断一个单词是否是另一个单词的“混合扩展”。 排序:按单词长度排序,以便我们可以从短到长处理单词。 动态规划: 使用动态规划来计算以每个单词结尾的最长链长度。 对于每个单词,检查所有比它短一个字母的单词,看看它们是否是“混合扩展”。 如果是,则更新当前单词的最长链长度和前驱索引。 输出:根据动态规划结果,输出最长链。

    代码实现

    以下是完整的 C++ 代码实现:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
     
    using namespace std;
     
    struct Word {
        char str[25];
        int hash[26] = {0};
        int len;
        int dp = 1;
        int pre = -1;
        
        void calculate_hash() {
            len = strlen(str);
            for (int i = 0; i < len; i++) {
                hash[str[i] - 'a']++;
            }
        }
        
        void print() const {
            printf("%s\n", str);
        }
    };
     
    bool compare_length(const Word& a, const Word& b) {
        return a.len < b.len;
    }
     
    void print_chain(const vector<Word>& words, int index) {
        if (index == -1) return;
        print_chain(words, words[index].pre);
        words[index].print();
    }
     
    int main() {
        vector<Word> words;
        char buffer[25];
        
        // 读取输入
        while (scanf("%s", buffer) != EOF) {
            Word word;
            strcpy(word.str, buffer);
            word.calculate_hash();
            words.push_back(word);
        }
        
        // 按长度排序
        sort(words.begin(), words.end(), compare_length);
        
        int max_index = 0;
        int max_length = 1;
        
        // 动态规划处理
        for (int i = 1; i < words.size(); i++) {
            for (int j = i - 1; j >= 0; j--) {
                // 只检查长度小1的单词
                if (words[j].len + 1 < words[i].len) break;
                if (words[j].len != words[i].len - 1) continue;
                
                int diff = 0;
                for (int k = 0; k < 26; k++) {
                    diff += abs(words[i].hash[k] - words[j].hash[k]);
                    if (diff > 2) break; // 提前终止
                }
                
                if (diff <= 2 && words[i].dp < words[j].dp + 1) {
                    words[i].dp = words[j].dp + 1;
                    words[i].pre = j;
                    
                    if (words[i].dp > max_length) {
                        max_length = words[i].dp;
                        max_index = i;
                    }
                }
            }
        }
        
        // 输出最长链
        print_chain(words, max_index);
        
        return 0;
    }
    

    代码解释

    Word 结构体: str:存储单词字符串。 hash:存储每个字母的频率。 len:单词长度。 dp:以当前单词结尾的最长链长度。 pre:前驱单词的索引。 calculate_hash():计算单词的字母频率。 print():打印单词。 compare_length:用于按单词长度排序的比较函数。 print_chain:递归打印最长链。 main 函数: 读取输入并存储到 words 向量中。 按单词长度排序。 使用动态规划计算最长链。 输出最长链。 动态规划部分详解 对于每个单词 i,检查所有比它短一个字母的单词 j。 计算 i 和 j 的字母频率差。如果差不超过 2(因为添加一个字母最多改变两个字母的频率),则 i 可以是 j 的“混合扩展”。 更新 i 的最长链长度和前驱索引。 跟踪最长链的结束索引 max_index 和长度 max_length。 输出部分 使用递归函数 print_chain 从最长链的结束索引开始,回溯打印整个链。

    • 1

    信息

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