题意:
给定一串数字,问这串数字可能代表的单词,若存在多个可能,输出单词数最少的情况,若还是相同输出任意符合的单词。数字转换规则就是根据手机的按键规则。
题解:
我们将所有单词转换成数字,然后保存到字典树中。然后开始dp给定的数字串,dp[i]表示从i开始到最后的数字串最少需要多少个单词构成。dp[i]=min(dp[k+1])(m>k>=i,且[i,k]数字串在字典树中存在)。由于要输出单词,所以用pre[i]记录i位置的下个单词位置,num[i]记录i位置后的单词编号。
代码:
#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <map> #include <vector> using namespace std; #define LL long long const int maxn=50001*51; const int INF=1e8; int f[27]={2,2,2,3,3,3,4,4,1,1,5,5,6,6,0,7,0,7,7,8,8,8,9,9,9,0}; struct Trie{ int ch[maxn][10]; int val[maxn]; int sz; Trie(){sz=1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) { return f[c-'a']; } void insert(char *s,int v) { int i,u=0,n=strlen(s); for(i=0;i<n;i++) { int c=idx(s[i]); if(!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[u][c]=sz++; } u=ch[u][c]; } val[u]=v; } }e; char a[50005][55]; char str[110]; int pre[110],num[110],dp[110],g[110],gg; int main() { while(scanf("%s",str)!=EOF) { if(str[0]=='-')break; int n; scanf("%d",&n); int i,j,k,u,m; memset(e.ch[0],0,sizeof(e.ch[0])); e.sz=1; for(i=1;i<=n;i++) { scanf("%s",a[i]); e.insert(a[i],i); } memset(pre,-1,sizeof(pre)); m=strlen(str); dp[m]=0; for(i=0;i<m;i++)dp[i]=INF; for(i=m-1;i>=0;i--) { u=0; for(j=i;j<m;j++) { int c=str[j]-'0'; if(!e.ch[u][c])break; u=e.ch[u][c]; if(e.val[u]) { if(dp[i]>dp[j+1]+1) { dp[i]=dp[j+1]+1; pre[i]=j+1; num[i]=e.val[u]; } } } } if(dp[0]==INF)printf("No solution.\n"); else { gg=0; k=0; while(pre[k]!=-1) { g[gg++]=num[k]; k=pre[k]; } for(i=0;i<gg;i++) { if(i==gg-1)printf("%s\n",a[g[i]]); else printf("%s ",a[g[i]]); } } } return 0; } /* 2 than that */