Letter Game题解
Letter games are popular at home and on television. In one version of the game, every letter has a value, and you collect letters to form one or more words giving the highest possible score. Unless you have `a way with words', you will try all the words you know, sometimes looking up the spelling, and then compute the scores. Obviously, this can be done more accurately by computer.
Given the values in Figure 1, a list of words, and the letters collected: find the highest scoring words or pairs of words that can be formed.
prmgroa
profile program prom rag ram rom .
On the first line, your program should write the highest possible score, and on each of the following lines, all the words and/or word pairs from file lgame.dict with this score. Sort the output alphabetically by first word, and if tied, by second word. A letter must not occur more often in an output line than in the input line. Use the letter values given in Figure 1.
When a combination of two words can be formed with the given letters, the words should be printed on the same line separated by a space. The two words should be in alphabetical order; for example, do not write `rag prom', only write `prom rag'. A pair in an output line may consist of two identical words.
This output uses the tiny dictionary above, not the lgame.dict dictionary.
24 program prom rag
在家里用电视机做字母游戏是很流行的,其中一种玩法是:每一个字母有一个数值与之对应.你收集字母组成一个或多个词以得到尽可能高的得分.除非你已有了 “找词的方法”(“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'是同样的词对,只输出字典顺序较小的那个。
输出要按照字典顺序排序,如果两个词对第一个单词的顺序相同,则按照第二个单词。一个词对中的两个单词可以相同。
prmgroa
profile program prom rag ram rom .
24 program prom rag
呵呵,这道题的题意有些难以捉摸。刚才开始的时候我WA了N次,仔细分析了题目才发现没看清题意。汗~~~
注意一下,这里所选的最大分值不一定要和输入的字符串完全匹配,只需在字典中找到单个或组合的最大值即可。
下面我们来考虑算法。对于单个的字符串在读入时可以直接判断。因为所有字符串长度都是3--7之内的,我们很快就会发现——如果组合的话,最多才2个。然而40000^2的效率仍然不可观。仔细看翻译中对输入字符串的描述“这就是收集到字母(就是可以使用的字母)”因此我们可以把字典中的字符串先进行一次判断。设给定字符串为S,字典中某字符串是P,如果P中含有S里不含有的字母,就可以直接踢掉。这样效率就非常可观了。我们在找最大分值的同时,也可以顺带地记录答案。
原始代码:(第三个点开始WA,以为要完全匹配)
{ PROG:lgame ID:juan1973 LANG:PASCAL } const rank:array['a'..'z'] of longint=(2,5,4,4,1,6,5,5,1,7,6,3,5,2,3,5,7,2,1,2,4,6,6,7,5,7); var temp,map:array['a'..'z'] of longint; ans:array[1..40001] of string; ok:array[1..40001,'a'..'z'] of longint; cnt,max,i,len,j,l:longint; flag:boolean; p,s:string; k:char; function check:boolean; var i:longint; begin for i:=1 to l do begin if (temp[p[i]]+1>map[p[i]]) then exit(false); temp[p[i]]:=temp[p[i]]+1; end; check:=true; end; begin assign(input,'lgame.in'); reset(input); assign(output,'lgame.out'); rewrite(output); readln(s); close(input); len:=length(s); for i:=1 to len do begin inc(map[s[i]]); inc(max,rank[s[i]]); end; writeln(max); assign(input,'lgame.dict'); reset(input); readln(p); while p<>'.' do begin l:=length(p); if (p='jacuzzi') then flag:=true; flag:=true; fillchar(temp,sizeof(temp),0); if check then begin if (l=len) then writeln(p) else begin inc(cnt); ok[cnt]:=temp; ans[cnt]:=p; end; end; readln(p); end; close(input); for i:=1 to cnt do for j:=i to cnt do begin flag:=true; for k:='a' to 'z' do if ok[i][k]+ok[j][k]<>map[k] then begin flag:=false;break;end; if flag then writeln(ans[i],' ',ans[j]); end; close(output); end.
{ PROG:lgame ID:juan1973 LANG:PASCAL } const rank:array['a'..'z'] of longint=(2,5,4,4,1,6,5,5,1,7,6,3,5,2,3,5,7,2,1,2,4,6,6,7,5,7); var temp,map:array['a'..'z'] of longint; ans:array[1..5001] of string; cnt,max,i,len,j,l,n:longint; p:array[1..40001] of string; t,s:string; function check(o:string):longint; var i:longint; begin check:=0;l:=length(o); for i:=1 to l do begin if (temp[o[i]]+1>map[o[i]]) then exit(0); temp[o[i]]:=temp[o[i]]+1; check:=check+rank[o[i]]; end; end; procedure find_max; var t,j,i:longint; begin for i:=1 to n do for j:=i to n do begin if length(p[i])+length(p[j])>len then continue; fillchar(temp,sizeof(temp),0); t:=check(p[i]+p[j]); if t>max then begin max:=t;cnt:=0;end; if t=max then begin cnt:=cnt+1;ans[cnt]:=p[i]+' '+p[j];end; end; end; procedure scanf; var t:longint;ss:string; begin readln(ss); while ss<>'.' do begin fillchar(temp,sizeof(temp),0); t:=check(ss); if t>0 then begin inc(n); p[n]:=ss; if (t>max) then begin max:=t;cnt:=0;end; if (t=max) then begin cnt:=cnt+1;ans[cnt]:=ss;end; end; readln(ss); end; end; begin assign(input,'lgame.in'); reset(input); assign(output,'lgame.out'); rewrite(output); readln(s); close(input); len:=length(s); for i:=1 to len do inc(map[s[i]]); assign(input,'lgame.dict'); reset(input); max:=0; scanf;find_max; writeln(max); for i:=1 to cnt-1 do for j:=i+1 to cnt do if (ans[i]>ans[j]) then begin t:=ans[i];ans[i]:=ans[j];ans[j]:=t;end; for i:=1 to cnt do writeln(ans[i]); close(input); close(output); end.