USACO-Section 4.3 Letter Game (枚举)

本文介绍了一种通过计算机寻找字母游戏中最高得分单词或单词组合的方法。利用特定的评分规则和给定的字母集合,从词典中筛选出符合条件的单词,并通过递归算法找出所有可能的高分组合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

Lgame.gif

在家里用电视机做字母游戏是很流行的,其中一种玩法是:每一个字母有一个数值与之对应.你收集字母组成一个或多个词以得到尽可能高的得分.除非你已有了 “找词的方法”(“a way with words”),你会把你知道的字都试一遍.有时你也许会查阅其拼写,然后计算得分。显然可以用计算机更为准确地完成此任务。上图示出了英文字母及其所对应的值,当给出英文单词(word) 的表列及收集的字母时,请找出所能形成的得分最高的词或词对(pairs of words)。

[编辑]格式

PROGRAM NAME: lgame

INPUT FORMAT:

(file lgame.in)

输入文件lgame.in中有一行由小写字母(`a'到`z')组成的字符串, 这就是收集到字母(就是可以使用的字母),字符串由至少3个字母至多7个字母(以任意顺序) 组成。

(file lgame.dict)

词典文件lgame.dict由至多40,000行组成,文件的最后一行有'.' 表示文件的结束。其它各行每一行都是由至少3个小写字母,至多7 个小写字母组成的字符串。文件中的词已按字典顺序排序。

OUTPUT FORMAT:

(file lgame.out)

在文件lgame.out的第一行,你的程序应写上最高得分(子任务A).使用上面图形中给出的字母-值对应表。

随后的每一行是由文件lgame.dict中查到的具有这个得分的所有的词和或词对(word pairs)(子任务B)。要利用图中给定的字母的值。

当两个词能够形成 一个组合(具有给定的字母)时,这两个词应该打印到同一行,两个词中间用一个空格隔开。不许重复表示词对,例如'rag prom'和'prom rag'是同样的词对,只输出字典顺序较小的那个。

输出要按照字典顺序排序,如果两个词对第一个单词的顺序相同,则按照第二个单词。一个词对中的两个单词可以相同。

[编辑]SAMPLE INPUT(file lgame.in)

prmgroa

[编辑]SAMPLE INPUT(file lgame.dict)

profile
program
prom
rag
ram
rom
.

[编辑]SAMPLE OUTPUT

24
program
prom rag

很容易就能想到枚举,而且数据量很小,复杂度够了


主要是各种字符串匹配比较麻烦,幸亏有STL库,要不然估计很难写出来


/*
ID: your_id_here
PROG: lgame
LANG: C++
*/
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <fstream>

using namespace std;

int sco[255],cnt[255]={0},tmp[255],maxv=0,len,ch[9];
int num[9],all=0;
bool vis[9];
string ori;
map<string,int> mp;
map<string,bool> used;
vector<string> ans;

void dfs(string pre,string s,bool isSec) {
    if(s.size()>=3) {
        if(mp[s]!=0) {
            if(s.size()==3&&!isSec&&len>=6)//因为最多只有7个字符,所以若存在两个字符串,则有一个必定为3个字符
                dfs(s,"",true);
            if(isSec) {
                if(maxv<=mp[pre]+mp[s]) {
                    if(maxv<mp[pre]+mp[s]) {//如果发现值更大的单词组
                        maxv=mp[pre]+mp[s];
                        ans.clear();
                        used.clear();
                    }
                    if(pre<=s) {
                        if(!used[pre+" "+s]) {//只放入为放入过的
                            used[pre+" "+s]=true;
                            ans.push_back(pre+" "+s);
                        }
                    }
                    else {
                        if(!used[s+" "+pre]) {
                            used[s+" "+pre]=true;
                            ans.push_back(s+" "+pre);
                        }
                    }
                }
            }
            else {
                if(maxv<=mp[s]) {
                    if(maxv<mp[s]) {
                        maxv=mp[s];
                        ans.clear();
                        used.clear();
                    }
                    if(!used[s]) {
                        used[s]=true;
                        ans.push_back(s);
                    }
                }
            }
        }
    }
    for(int i=0;i<all;++i) {
        if(num[i]>0) {
            --num[i];
            string tmp=s;
            tmp.push_back(ch[i]);
            dfs(pre,tmp,isSec);
            ++num[i];
        }
    }
}

int main() {
    ifstream fin("lgame.in");
    ifstream dict("lgame.dict");
    ofstream fout("lgame.out");

    sco['q']=sco['j']=sco['z']=sco['x']=7;
	sco['w']=sco['f']=sco['k']=sco['v']=6;
	sco['y']=sco['p']=sco['g']=sco['h']=sco['b']=sco['m']=5;
	sco['u']=sco['d']=sco['c']=4;
	sco['o']=sco['l']=3;
	sco['r']=sco['t']=sco['a']=sco['n']=2;
	sco['e']=sco['i']=sco['s']=1;

    string s;
    fin>>ori;
    len=ori.size();
    for(int i=0;i<len;++i)//统计各单词出现
        ++cnt[ori[i]];
    for(int i='a';i<='z';++i)
        if(cnt[i]) {//将字符分组,可以避免同一个单词多次出现,相当于剪枝
            ch[all]=i;
            num[all++]=cnt[i];
        }
    while(dict>>s&&s[0]!='.') {
        memset(tmp,0,sizeof(tmp));
        for(int i=0;i<s.size();++i)
            ++tmp[s[i]];
        int tot=0;
        for(int i='a';i<='z';++i)
            if(tmp[i]>cnt[i]) {//若字典中的单词i字符个数 大于 ori中i字符个数,则该单词无效
                tot=-1;
                break;
            }
            else
                tot+=tmp[i]*sco[i];
        if(tot!=-1)//若ori串能形成当前串,则记录其分值
            mp[s]=tot;
    }
    dfs("","",false);
    fout<<maxv<<"\n";
    sort(ans.begin(),ans.end());//要按升序输出
    for(int i=0;i<ans.size();++i)
        fout<<ans[i]<<"\n";
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值