timus 1002. Phone Numbers(KMP&动态规划)
2016-03-18 01:54
549 查看
题目链接
1002. Phone Numbers题意
现实生活中,你时常会遇到许多许多而且越来越长的电话号码。你需要记住这类型的号码。 例如按下面的图示,把字母划分到特定的数字上,是一种很容易就能把数字记住的方法:1 ij 2 abc 3 def 4 gh 5 kl 6 mn 7 prs 8 tuv 9 wxy 0 oqz
按这种方法:每个字或一个词组可被代替成一组特定的数字,那么,你只可以通过记住一些词就能记住相应电话号码。 如果可以找出一种单词与个人电话号码的简单关系,它是很有吸引力的。例如你的一个棋友的电话号码是941837296,你可以用 WHITEPAWN来代替;又如你可以用BUULDOG来代替你的一个喜爱的老师的电话号码:2855304。
问题
对给定的给定的数字和单词表,求出一个最简短的单词序列(也就是得出一尽可能短的单词来代替相应的数字)。这种对应关系要求符合上图所描述的关系。输入
输入包含若干组的测试数据。每组测试点的第一行是你所要记住的电话号码。这个号码最多有100个数位。测试的第二行是单词总数(最大为50000个)。以下的每一行是只包含一个单词,单词长度最大限制为50个字母。整个输入文件的大小不超过300KB。 输入文件的最后一行以-1作为结束标志。输出
输出文件的每一行为找到的最短单词序列。每个单词间用一个空格隔开。如果没有解决方案,则输出“No solution.”。 如果有多个单词满足条件,可以从中选择任一个单词输出。样例
input
7325189087 5 it your reality real our 4294967296 5 it your reality real our -1
output
reality our No solution.
思路
首先,因为每个字母都对应唯一一个数字,我们完全可以将所有给定单词转换为数字序列。那么,现在的问题就是用最少的数字串组成主串,我们用kmp找出每个数字串在主串中匹配的位置。
若匹配成功,那么在主串中匹配的首尾位置可以看作是一个权值为1的单向边,问题就可以转换为求0~n的最短路问题。
因为这题的每条边的先后次序是确定的,所以直接用dp解决即可。
代码
#include <iostream> #include <cstring> #include <math.h> #include <cstdio> #include <stack> using namespace std; const int N = 109; const int M = 50009; int p , d , v ; int g ; int fa ; int l[M]; char s[59], z[M][59]; int t[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 }; int nxt[59]; void getNext(int d[], int length) { nxt[0] = 0; for(int i=1, k=0; i<length; i++) { while(k && d[i] != d[k]) k = nxt[k-1]; nxt[i] = d[i] == d[k] ? ++k : 0; } } void kmp(int b[], int d[], int len, int length, int pos) { getNext(d, length); for(int i=0, k=0; i<len; i++) { while(k>0 && d[k] != p[i]) k = nxt[k-1]; if(d[k] == p[i]) k++; if(k == length) g[i-length+1][i+1] = pos; } } bool solve(int len) { memset(v, 0x3f, sizeof(v)); v[0] = 0; for(int i=0; i<len; i++) for(int j=i+1; j<=len; j++) if(g[i][j] != -1 && v[i]+1 < v[j]) { v[j] = v[i] + 1; fa[j] = g[i][j]; } return v[len] < 0x3f3f3f3f; } void print(int now) { if(now - l[fa[now]] > 0) { print(now-l[fa[now]]); printf(" "); } printf("%s", z[fa[now]]); } int main() { int n; while(~scanf("%s", s)) { if(s[0] == '-') break; memset(g, -1, sizeof(g)); int len = strlen(s); for(int i=0; i<len; i++) p[i] = s[i]-'0'; scanf("%d", &n); for(int i=0; i<n; i++) { scanf("%s", z[i]); l[i] = strlen(z[i]); for(int j=0; j<l[i]; j++) d[j] = t[z[i][j]-'a']; kmp(p, d, len, l[i], i); } if(solve(len)) print(len); else printf("No solution."); printf("\n"); } return 0; }
相关文章推荐
- ActiveMQ
- android:configChanges属性
- Unity Shaders and Effects Cookbook (1-3) 创建 Half Lambert 光照模型
- android_广播者_监听短信
- 多字符集(ANSI)和UNICODE及字符串处理方式准则
- Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果
- Geek爱旅行 - Photoshop超现实场景
- Geek爱旅行 - Photoshop超现实场景
- UNICODE和ANSI字符串的转换(解释了MultiByteToWideChar,WideCharToMultiByte,GetTextCharsetInfo,GetTextCharset,IsDBCSLeadByte,IsDBCSLeadByteEx,IsTextUnicode一共7个函数)
- Hadoop实战: Linux报 tmp 磁盘存储不足
- 分布式系统了的一些看法
- 数据库的管理
- 关于LGAME使用心得
- Note of Vim
- 利用red5搭建一个简单的流媒体直播系统
- BOOST_FOREACH遍历
- Android 之 应用程序和Activity
- Java Listener 模式
- android_广播接受者_监听开机启动和IP拨号
- 检查系统版本