您的位置:首页 > 其它

URAL 1002|Phone Numbers|动态规划

2017-10-03 21:03 211 查看
http://acm.timus.ru/problem.aspx?space=1&num=1002

题目翻译

现代社会中,你常常会遇到一大堆电话号码,而且这些号码正在变得越来越长,你却需要记住这些号码。一种简易的解决方法是建立数字与字母的对应关系,比如下面这种:

1 ij    2 abc   3 def
4 gh    5 kl    6 mn
7 prs   8 tuv   9 wxy
0 oqz


这样一个数字关联一些字母,这样你可以通过记单词的方式记忆号码。显然如果能找到号码与单词之间的简单的联系是坠吼的。比如你的一个棋友的电话号码是941837296,你可以读作WHITEPAWN,你最喜欢的老师的电话号码是2855304,则可以读作BULLDOG。

你需要写一个程序,找出单词数目最少的一组单词,其可以表示对应的电话号码。对应关系如上。

输入

输入包含多组测试数据。对于每组数据,第一行电话号码,第二行一个正整数n(n≤50,000),表示字典里有多少个单词供你记忆。接下来n行,每行一个字符串,表示可以组成句子的单词,单词最多50个字符,均为小写英文字母。输入文件不超过300KB。输入文件最后一行-1表示输入结束。

输出

对于每组数据,输出一行,如果存在这样的一种表示方式,则输出对应的句子,如果存在多种句子符合条件,输出单词数目最少的那个,如果还存在多种句子符合条件,随便输出一种。如果不存在,输出”No solution.”。

样例输入

7325189087
5
it
your
reality
real
our
4294967296
5
it
your
reality
real
our
-1


样例输出

reality our
No solution.


题解

令dpi表示电话号码前i位可以用一个句子表示的话,最少的单词数目。

那么显然有

dpi=minj{dpi−lenj+1}(mappedwordj=calli−lenj+1..i)

其中
mapped_word
表示单词对应的号码是多少。

#include <cstdio>
#include <cstring>
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define rep(i,j,k) for(i=j;i<k;++i)
const char map[] = "22233344115566070778889990";

char s[128], word[65536][64];
int len[65536], dp[128], sel[128];

void output(int n) {
if (n == 0) return;
else output(n - len[sel
]);
printf("%s ", word[sel
] + 1);
}

int main() {
int i, j, k, n, l;
while (scanf("%s", s + 1) != EOF && s[1] != '-') {
scanf("%d", &n); l = strlen(s + 1);
memset(dp, 127, sizeof dp);
dp[0] = 0;
FOR(i,1,n) scanf("%s", word[i] + 1), len[i] = strlen(word[i] + 1);
FOR(j,1,l) FOR(i,1,n) if (j >= len[i]) {
bool flag = true;
FOR(k,1,len[i]) if (s[j - len[i] + k] != map[word[i][k] - 'a']) {
flag = false;
break;
}
if (!flag) continue;
if (dp[j] > dp[j - len[i]] + 1) {
dp[j] = dp[j - len[i]] + 1;
sel[j] = i;
}
}
if (dp[l] == 0x7f7f7f7f) puts("No solution.");
else output(l), putchar('\n');
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: