首页 > 其他分享 >『题解』UVA 148 Anagram checker

『题解』UVA 148 Anagram checker

时间:2022-11-26 21:55:55浏览次数:82  
标签:Word 短语 题解 单词 checker str Trait Anagram Phrase

题目传送门


分析

貌似除了递归式暴力搜索外,没有其它的有效算法了。这样的话,对代码性能的要求就比较高了,为了快速的判断一个短语是否包含某个单词,必须找出一种特定的数据结构来表示。

我的方法是给每个单词附加一个 \(26\) 字节长度的数组,各个元素分别代表 \(a, b,...,z\) 这 \(26\)个字母在单词中出现的次数,把这个数组称为字符串的特征(简称特征)。对于短语也同样处理(忽略中间的空格),如果短语的特征均大于或等于某个单词的特征,即可判定该短语包含该单词。如果要在短语中删除或添加某个单词,只需对特征进行加减即可。

递归的过程是:从字典的第一个单词开始查找,找到第一个能被短语包含的单词,从短语特征中减掉这个单词并将该单词加入结果列表;然后将字典的起点移动到这个单词之后,开始下一级递归调用。如果下一级返回,则重新恢复原短语特征(再加上前面的单词)并从结果集中移除该单词,继续向字典后面查找。如果在某一级调用的开始发现短语特征已经减为\(0\),则说明已经找到可以重组为该短语的单词集,按要求输出结果即可(注意排除单词集与短语中的单词列表完全重合的情况)。

在具体实现中,我将结果集直接生成为字符串是为了代码比较清晰,如果要追求效率应另用链表或双端队列来保存,以加快添加和删除的速度。

\(Code\)

#include <bits/stdc++.h>
using namespace std;
struct WORD {
    string str; char Trait[26];
    bool operator>=(const WORD &Other) { //比较两个单词的特征,确定是否包含
        int i = 0;
        for (; i < 26 && Trait[i] >= Other.Trait[i]; ++i);
        return (i == 26); //全部特征都大于或等于时,判定存在包含关系
    }
    WORD& operator-=(const WORD &Other) { //从前一个单词中减掉后面的单词
        for (int i = -1; ++i < 26; Trait[i] -= Other.Trait[i]); //特征操作
        return *this;
    }
    WORD& operator+=(const WORD &Other) { //在前面一个单词中加上后面的单词
        for (int i = -1; ++i < 26; Trait[i] += Other.Trait[i]); //特征操作
        return *this;
    }
};
void GenTrait(const char *Str, char *Trait) { //根据字符串生成特征
    for (fill(&Trait[0], &Trait[26], 0); *Str != 0; ++Trait[*Str++ - 'A']);
}
typedef vector<WORD>::const_iterator DICTITER;
//递归搜索,iBeg和iEnd为搜索字典段的起点和终点。字典必须有序
void SearchAnagram(DICTITER iBeg, DICTITER iEnd, WORD &Phrase) {
    int nZeroCnt = 0;
    string &str = Phrase.str;
    //判断短语中所有字母是否都以在字典中找到
    for (; nZeroCnt < 26 && Phrase.Trait[nZeroCnt] == 0; ++nZeroCnt);
    if (nZeroCnt == 26) { //所有字母都找到,输出结果
        istringstream ss(str); //判定找到的单词集是否和原单词集相同
        vector<string> SrcWords, GenWords;
        //从输出字符串中提取原短语中的单词列表和查找到的单词集
        for (string Word; ss >> Word && Word != "="; SrcWords.push_back(Word));
        for (string Word; ss >> Word; GenWords.push_back(Word));
        //对原短语中的单词列表排序。查找到的单词集已有序
        sort(SrcWords.begin(), SrcWords.end());
        if (SrcWords != GenWords) { //判定是否相同
            cout << str << endl; //不同时输出结果
        }
        return; //返回上一级调用
    }
    //从指定的开始到结束,查找字典段中是否有单词被短语包含
    for (DICTITER i = iBeg; i != iEnd; ++i) {
        if (Phrase >= *i) { //根据特征进行查找
            Phrase -= *i; //将该单词的特征从短语特征中减掉
            str.push_back(' '); //结果字符串的最后加上该短语
            str.append(i->str);
            SearchAnagram(i + 1, iEnd, Phrase); //进入下一级查找过程
            str.erase(str.length() - i->str.length() - 1); //恢复结果字符串
            Phrase += *i; //恢复短语特征
        }
    }
}
//主函数
int main(void) {
    vector<WORD> Dict, Subset;
    //读入所有字典,并生成每个单词的特征
    for (WORD Word; cin >> Word.str && Word.str != "#";) {
        GenTrait(Word.str.c_str(), Word.Trait);
        Dict.push_back(Word);
    }
    //读入所有的短语,逐个处理
    for (string Line; getline(cin, Line) && Line != "#"; Subset.clear()) {
        WORD Phrase = {Line}; //保留原短语字符串
        //删除指定短语中的空格(准备生成特征)
        Line.erase(remove(Line.begin(), Line.end(), ' '), Line.end());
        if (Line.empty()) {
            continue;
        }
        GenTrait(Line.c_str(), Phrase.Trait); //生成特征
        //在字典中筛选中被原短语包含的单词,用作查找
        for (vector<WORD>::iterator i = Dict.begin(); i != Dict.end(); ++i) {
            if (Phrase >= *i) { //根据特定判断是否被包含
                Subset.push_back(*i);
            }
        }
        Phrase.str.append(" ="); //按照格式,在原短语后加上空格和=号
        SearchAnagram(Subset.begin(), Subset.end(), Phrase); //递归查找过程
    }
    return 0;
}

标签:Word,短语,题解,单词,checker,str,Trait,Anagram,Phrase
From: https://www.cnblogs.com/mrCrazyWolf/p/16928420.html

相关文章

  • 『题解』UVA 12676 Inverting Huffman
    题目传送门题意静态哈夫曼编码是一种主要用于文本压缩的编码算法。给定一个由\(N\)个不同字符组成的特定长度的文本,算法选择\(N\)个编码,每个不同的字符一个编码。使......
  • 『题解』Codeforces 1743A Password
    Problem现有\(4\)位密码,满足以下条件:给定数位的集合\(S\),密码中没有用到这些数位。密码中恰好包含两个数位,每个数位出现了两次。求符合条件的密码个数。Solution......
  • 『题解』Codeforces 1742C Stripes
    Problem在\(8\times8\)的网格上,轮流染上红色和蓝色。红色只能染一整行。蓝色只能染一整列。问最后用的是哪种颜色。Solution题目说明了至少会染一个条纹,所以我......
  • 『题解』Codeforces 1702A Round Down the Price
    题意这道题其实就是让你求出当前数字与\(10\)的整数幂次的差值(注意不能向上取,只能向下取)。而且题目也标注了\(1\lek\le9\),所以我们可以让\(i\)从\(0\sim9\)......
  • IOS13及以上Fiddler不能抓包问题解决
    iOS 上一般情况下信任HTTPS证书即可抓HTTPS的包(除非APP开启了防止抓包),但最近发现iOS 13以上出现即使安装并信任了证书,当用safari浏览百度时仍出现是否信任该网站......
  • dp完全背包问题解组合问题——零钱兑换
    本题为完全背包问题,遍历容量需要顺序遍历classSolution{public:intchange(intamount,vector<int>&coins){//完全背包顺序遍历//背包容量为a......
  • 题解 P7623 [AHOI2021初中组] 收衣服
    我还在小学的时候以现在初中名义我大五十牛逼参加了这次,然后身败名裂死磕这道题不会,现在觉得自己好傻啊233333显然这是要统计每个区间的贡献,所以我们可以打出来这个暴力,......
  • [蓝桥杯 2022 省 A] 填空问题 题解
    题目传送门这是一道提交答案题,也可以说是一道数学题。第一题我们先来看第一题。由于二维码在纸的中间部分,所以一开始要先裁剪\(4\)刀,这点题目也说了。其次,题目中展......
  • [传智杯 #4 初赛] 竞争得分 题解
    题目传送门这道题主要考察的是"打擂台"算法,也就是求最大或求最小值。就像这样:if(x>maxn)maxn=x;也可以写成这样:maxn=max(maxn,x);最小值同理。然而光......
  • python(牛客)试题解析3 - 困难
    导航一、找到已经最大承重的背包内如何放入最大价值的物品的最优解二、查找一个字符串中包含另外一个字符串(可打乱顺序)的次数三、计算正整数数组从头走到最后一个成员......