把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

USACO4.3 Letter Game【枚举·细节】

题意

这道题的题目描述让我好一阵蒙,简述一下题意吧:

给定一些字母的价值(如图所示),给出一个字符串(长度在$3$到$7$之间,可以出现重复的字母)和一个单词库。定义一个单词的价值就是它的字母的价值之和,一组单词的价值就是所有单词的价值之和,一组单词中的单词数量$>=1$,一组单词中的单词可以重复。要求用字符串中的字母拼成单词库中的一组单词,字符串中的字母不可以重复使用(如果字符串中有多个相同的字母,那么这个字母只能用出现的那么多次),求能够得到的单词组的最大价值并输出所有方案(按字典序)

分析

发现字符串的长度在$3$到$7$之间,单词的长度也在长度在$3$到$7$之间,说明一组单词最多有$2$个。

给出的词库大小是$40000$,但是字符串的只在$3$到$7$之间,也就是最多只有$7$种字母,所以有大量的单词实际上是不合法的,我们可以在输入的时候把它们去掉,只保存有用的单词。

更新一组里面只有一个单词的答案,然后两两枚举单词(一组),更新答案。

利用题目给出的单词库本身按字典序排的性质,有序地遍历就可以保证顺序(良心题目)

  1 /*
  2 ID: Starry21
  3 LANG: C++
  4 TASK: lgame           
  5 */ 
  6 #include<cstdio>
  7 #include<algorithm>
  8 #include<vector>
  9 #include<cstring>
 10 #include<queue>
 11 using namespace std;
 12 #define ll long long
 13 #define INF 0x3f3f3f3f
 14 const int v[28]={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};
 15 char s[10];
 16 int cnt[30],c1[40005][30],c2[30];
 17 char dic[40005][10];
 18 int len[40005],val[40005];
 19 int n;
 20 int ans[40005][2];
 21 int num,maxx=0;
 22 void get(int i,int j)
 23 {
 24     int res=val[i]+val[j];
 25     if(res<maxx) return ;
 26     if(res>maxx)
 27     {
 28         maxx=res;
 29         num=0;//找到了更大的答案 重新来过 
 30         //ans[++num][0]=i,ans[num][1]=j;会在下面一个if里再算一次答案 
 31     } 
 32     if(res==maxx)
 33         ans[++num][0]=i,ans[num][1]=j;
 34     return ;
 35 }
 36 int main() 
 37 {
 38     //freopen("lgame.in","r",stdin);
 39     scanf("%s",s+1);
 40     for(int i=1;i<=strlen(s+1);i++)
 41         cnt[s[i]-'a']++;
 42     //freopen("lgame.dict","r",stdin);
 43     //freopen("lgame.out","w",stdout);
 44     while(scanf("%s",s+1)!=EOF)
 45     {
 46         if(s[1]=='.') break;
 47         n++;
 48         memcpy(c1[n],cnt,sizeof(cnt));
 49         int tmp=0;
 50         bool f=0;
 51         for(int i=1;i<=strlen(s+1);i++)
 52         {
 53             c1[n][s[i]-'a']--;
 54             if(c1[n][s[i]-'a']<0)
 55             {
 56                 f=1;
 57                 n--;
 58                 break;
 59             }
 60             tmp+=v[s[i]-'a'];
 61         }
 62         if(f) continue;
 63         strcpy(dic[n]+1,s+1);
 64         //puts(dic[n]+1);
 65         val[n]=tmp;
 66         len[n]=strlen(s+1);
 67         
 68     }//printf("%d\n",n);
 69     for(int i=1;i<=n;i++)
 70     {
 71         //puts(dic[i]+1);
 72         get(i,0);
 73         for(int j=i+1;j<=n;j++)//字典序 1~i-1 get(j,i)不能保证第一个小 
 74         {
 75             bool f=0;
 76             memcpy(c2,c1[i],sizeof(c1[i]));
 77             for(int k=1;k<=len[j];k++)
 78             {
 79                 c2[dic[j][k]-'a']--;
 80                 if(c2[dic[j][k]-'a']<0)
 81                 {
 82                     f=1;
 83                     break;
 84                 }
 85             }
 86             if(f) continue;
 87             get(i,j);//字典序 
 88         }
 89     }
 90     printf("%d\n",maxx);
 91     for(int i=1;i<=num;i++)
 92     {
 93         printf("%s",dic[ans[i][0]]+1);
 94         if(ans[i][1]) printf(" %s",dic[ans[i][1]]+1);
 95         puts("");
 96     }
 97     return 0;
 98 }
 99 /*
100 prmgroa
101 profile
102 program
103 prom
104 rag
105 ram
106 rom
107 .
108 */
Code

 

posted @ 2019-11-06 21:55  Starlight_Glimmer  阅读(149)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end