最近开始刷Ural,这三天先做了1000~1005,和十多道水题都算不上的题。。。
Ural 1002
Background
现实生活中,你时常会遇到许多许多而且越来越长的电话号码。你需要记住这类型的号码。 例如按下面的图示,把字母划分到特定的数字上,是一种很容易就能把数字记住的方法:
1 ij 2 abc 3 def 4 gh 5 kl 6 mn 7 prs 8 tuv 9 wxy 0 oqz
按这种方法:每个字或一个词组可被代替成一组特定的数字,那么,你只可以通过记住一些词就能记住相应电话号码。 如果可以找出一种单词与个人电话号码的简单关系,它是很有吸引力的。例如你的一个棋友的电话号码是941837296,你可以用 WHITEPAWN来代替;又如你可以用BULLDOG来代替你的一个喜爱的老师的电话号码:2855304。
[编辑] Problem
对给定的给定的数字和单词表,求出一个最简短的单词序列(也就是得出一尽可能短的单词来代替相应的数字)。这种对应关系要求符合上图所描述的关系。
[编辑] Input
输入包含若干组的测试数据。每组测试点的第一行是你所要记住的电话号码。这个号码最多有100个数位。测试的第二行是单词总数(最大为50000个)。以下的每一行是只包含一个单词,单词长度最大限制为50个字母。整个输入文件的大小不超过300KB。 输入文件的最后一行以-1作为结束标志。
[编辑] Output
输出文件的每一行为找到的最短单词序列。每个单词间用一个空格隔开。如果没有解决方案,则输出“No solution.”。 如果有多个单词满足条件,可以从中选择任一个单词输出。
[编辑] Sample Input
7325189087 5 it your reality real our 4294967296 5 it your reality real our -1
[编辑] Sample Output
reality our No solution.
一开始用的三维时间,二维空间的算法,不知是如何想的,后来改成O(n^2)的了。
很简单的一道题,有人把它看作是背包,但是我觉得完全没有必要再把这样的题还映射到某个模型了。
f[i] = min(f[i - len[j]]+1) if(NUM[i-len[j],i] == WRD[j])
考虑到字母到数字的映射是多对一的,因此我们就映射字母到数字。
另外,本题要注意边界。就是f[len[j]] = 1 if(NUM[len[j]] == WRD[j])
还有要注意,这道题最好将转移数组f的下界从0开始,和这个string的下界同步-_-b,同时也因为这个原因,要单独进行以上的初始化,否则,直接从f[0]转移过来就好了,不用单独初始化
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
using std::min;
using std::string;
using std::cout;
using std::cin;
string PN;
string wrds[50010];
string wrds2[50010];
char chrctr[26] = {'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'};
long length[50010];
long f[50010];
long g[50010];
long pnlen;
long n;
void dp()
{
for (long i=0;i<pnlen;i++)
{
g[i] = 0;
f[i] = 0x7f7f7f7f;
}
for (long i=1;i<n+1;i++)
{
if (PN.compare(0,length[i],wrds[i],0,length[i])==0)
{
f[length[i]-1] = 1;
g[length[i]-1] = i;
}
}
for (long i=1;i<pnlen;i++)
{
for (long j=1;j<n+1;j++)
{
if (i-length[j]>=0 && PN.compare(i-length[j]+1,length[j],wrds[j],0,length[j])==0)
{
if (f[i-length[j]]+1 < f[i])
{
f[i] = f[i-length[j]]+1;
g[i] = j;
}
}
}
}
}
void ou(long l)
{
if (g[l] == 0)return;
ou(l-length[g[l]]);
cout << wrds2[g[l]] << " ";
}
void translate(long l)
{
for (long i=0;i<length[l];i++)
{
wrds[l][i] = chrctr[wrds[l][i]-'a'];
}
}
int main()
{
freopen("phone.in","r",stdin);
freopen("phone.out","w",stdout);
while (1)
{
cin >> PN;
if (PN == "-1") break;
pnlen = PN.length();
cin >> n;
for (long i=1;i<n+1;++i)
{
cin >> wrds[i];
wrds2[i] = wrds[i];
length[i] = wrds[i].length();
translate(i);
}
dp();
if (f[pnlen-1]<0x7f7f7f7f) ou(pnlen-1);
else cout << "No solution.\n";
cout << "\n";
}
}