usaco training 4.3.4 Letter Game 题解

Letter Game题解
IOI 1995
 
Figure 1: Each of the 26 lowercase letters and its value

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.

PROGRAM NAME: lgame

INPUT FORMAT

One line with a string of lowercase letters (from ` a ' to ` z '). The string consists of at least 3 and at most 7 letters in arbitrary order.

SAMPLE INPUT (file lgame.in)

prmgroa

DICTIONARY FORMAT

At most 40,000 lines, each containing a string of at least 3 and at most 7 lowercase letters. At the end of this file is a line with a single period (` . '). The file is sorted alphabetically and contains no duplicates.

SAMPLE DICTIONARY (file lgame.dict)

profile
program
prom
rag
ram
rom
.

OUTPUT FORMAT

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.

SAMPLE OUTPUT (file lgame.out)

This output uses the tiny dictionary above, not the lgame.dict dictionary.

24
program
prom rag


描述

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


呵呵,这道题的题意有些难以捉摸。刚才开始的时候我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.

最终AC代码:

{
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.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值