1002 Phone Numbers 字符串dp
/*
字符串DP,但是要找到用最小的字符串来匹配,所以用dp储存当前所使用过的字符串数。
打印路径的话直接用数组表示前缀
*/
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
using namespace std;
string s = "22233344115566070778889990";
#define X 50010
int dp[X],pre[X],len[X],p[X],L;
string a[X],in[X],b;
void change(int x)
{
len[x] = in[x].size();
for(int i=0;i<len[x];i++)
a[x].push_back(s[in[x][i]-'a']);
}
bool check(int i,int j) //判断是否匹配
{
for(int k=len[j]-1;k>=0;k--)
if(b[i-1]==a[j][k])
i--;
else
return false;
return true;
}
void print(int x) //递归打印路径
{
if(p[x]>0)
{
print(p[x]);
cout<<" ";
}
cout<<in[pre[x]];
}
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
int n;
while(cin>>b,b[0]!='-')
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>in[i];
change(i);
}
memset(pre,-1,sizeof(pre));
memset(p,-1,sizeof(p));
L = b.size();
memset(dp,-1,sizeof(dp));
dp[0] = 0;
for(int i=1;i<=L;i++)
{
for(int j=0;j<n;j++)
if(len[j]<=i&&b[i-1]==a[j][len[j]-1]&&check(i,j))
{
if(dp[i-len[j]]==-1) //若前面不能匹配的话
continue;
int x;
if(dp[i]==-1) //当前还没有其他的字符串匹配
x = dp[i-len[j]]+1;
else //当前已经有其他字符串,取最小的那个
x = min(dp[i],dp[i-len[j]]+1);
if(dp[i]!=x) //若当前的还没匹配或者当前的比以前匹配过的所用字符串数目少,更新
{
dp[i] = dp[i-len[j]]+1;
pre[i] = j;
p[i] = i-len[j];
}
}
}
if(dp[L]<0)
cout<<"No solution."<<endl;
else
{
print(L);
cout<<endl;
}
}
return 0;
}