题意:每个小写字母对应一个数字,然后给你一串数字和一些单词,找出一些单词对应这些数字,并且使得用的单词数最少。
题解:dp[i]代表覆盖住前i个数字的最小花费,如果s能覆该[i,j]则dp[j]=min(dp[j],dp[i-1]+1),判断能否覆盖方法就多了KMP/HASH/AC自动机都行,map也可以水过。
View Code
1 #include<cstdio> 2 #include<cstring> 3 #include<map> 4 #include<string> 5 using namespace std; 6 const int inf=1000000; 7 int ma[300],lm[50020]; 8 map<string,int> md; 9 char word[50020][70]; 10 int dp[120],pre[120]; 11 int main() 12 { 13 ma['i']=ma['j']='1'; 14 ma['a']=ma['b']=ma['c']='2'; 15 ma['d']=ma['e']=ma['f']='3'; 16 ma['g']=ma['h']='4'; 17 ma['k']=ma['l']='5'; 18 ma['m']=ma['n']='6'; 19 ma['p']=ma['r']=ma['s']='7'; 20 ma['t']=ma['u']=ma['v']='8'; 21 ma['w']=ma['x']=ma['y']='9'; 22 ma['o']=ma['q']=ma['z']='0'; 23 char s[120]; 24 int n; 25 while(scanf("%s",s+1)!=EOF) 26 { 27 md.clear(); 28 scanf("%d",&n); 29 int i,j,k; 30 for(i=1; i<=n; i++) 31 { 32 scanf("%s",word[i]); 33 char tp[70]; 34 for(j=0;word[i][j];j++) 35 tp[j]=ma[word[i][j]]; 36 tp[lm[i]=j]='\0'; 37 md[tp]=i; 38 } 39 memset(pre,-1,sizeof(pre)); 40 for(i=110;i>0;i--) 41 dp[i]=inf; 42 dp[0]=0; 43 for(i=1;s[i]!='\0';i++) 44 { 45 if(dp[i-1]==inf) 46 continue; 47 if(md.find(s+i)!=md.end()) 48 { 49 k=md[s+i]; 50 if(dp[i-1+lm[k]]>dp[i-1]+1) 51 { 52 dp[i-1+lm[k]]=dp[i-1]+1; 53 pre[i-1+lm[k]]=k; 54 } 55 } 56 for(j=i+1;s[j]!='\0';j++) 57 { 58 char ch=s[j]; 59 s[j]='\0'; 60 if(md.find(s+i)!=md.end()) 61 { 62 k=md[s+i]; 63 if(dp[i-1+lm[k]]>dp[i-1]+1) 64 { 65 dp[i-1+lm[k]]=dp[i-1]+1; 66 pre[i-1+lm[k]]=k; 67 } 68 } 69 s[j]=ch; 70 } 71 } 72 if(dp[--i]==inf) 73 printf("No solution.\n"); 74 else 75 { 76 int wos[200],top=0; 77 for(; i!=0; i-=lm[pre[i]]) 78 wos[top++]=pre[i]; 79 for(int i=top-1; i>0; i--) 80 printf("%s ",word[wos[i]]); 81 printf("%s\n",word[wos[0]]); 82 } 83 } 84 return 0; 85 }