timus 1002. Phone Numbers(KMP&动态规划)

题目链接

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[N], d[N], v[N];
int g[N][N];
int fa[N];
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;
}
时间: 2024-10-01 05:54:44

timus 1002. Phone Numbers(KMP&动态规划)的相关文章

Timus : 1002. Phone Numbers 题解

把电话号码转换成为词典中能够记忆的的单词的组合,找到最短的组合. 我这道题应用到的知识点: 1 Trie数据结构 2 map的应用 3 动态规划法Word Break的知识 4 递归剪枝法 思路: 1 建立Trie字典树.方便查找, 可是字典树不是使用字符来建立的.而是把字符转换成数字.建立一个数字字典树. 然后叶子节点设置一个容器vector<string>装原单词. 2 动态规划建立一个表,记录能够在字典树中找到的字符串的前缀子串 3 假设找到整个串都在字典树中,那么就能够直接返回这个单词

Timus 2070 Interesting Numbers

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=2070 题目描述: 题目大意是给定范围[L, R],求该范围中interesting数的个数. interesting数的定义为: 1.素数 2.不为素数且其正因子的个数不为素数个(如:6: 1,2,3,6) 计算正因子的个数一般使用的是分解质因数了,若 n = p1^a1 * p2^a2 * ... pm^am 那么正因子的个数为 k = (a1+1) * (a2+1) * ... * (am

Timus Online Judge1009---K-based Numbers(简单递推dp)

Let's consider K-based numbers, containing exactly N digits. We define a number to be valid if its K-based notation doesn't contain two successive zeros. For example: 1010230 is a valid 7-digit number; 1000198 is not a valid number; 0001235 is not a

bzoj 3670 动物园 - kmp - 动态规划

Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习算法. 某天,园长给动物们讲解KMP算法. 园长:“对于一个字符串S,它的长度为L.我们可以在O(L)的时间内,求出一个名为next的数组.有谁预习了next数组的含义吗?” 熊猫:“对于字符串S的前i个字符构成的子串,既是它的后缀又是它的前缀的字符串中(它本身除外),最长的长度记作next[i].

算法习题分类

My Travel Of Acm! 早早的结束了考试,最近任务不是那么重,就花点时间整理了一下大二上学期学习过的一些算法 --2019-01-06 分类 知识清单 数据结构 树状数组 STL 差分数组 树链剖分 图论 图的连通性问题 2-SAT LCA 字符串 AC自动机 KMP 动态规划 动态规划(基础)       原文地址:https://www.cnblogs.com/violet-acmer/p/10228028.html

HDOJ 1002 A + B Problem II (Big Numbers Addition)

题目链接在此?http://acm.hdu.edu.cn/showproblem.php?pid=1002 这题也比较简单,只需要开三个长度为1000的char数组来分别储存a.b.ans,再利用我们加法的算法,先向右对齐再相加.注意一下进位时的特殊情况就好了. 不过笔者的代码写好后提交上去,两次Presentation Error,然后才发现只是最后多输出一个空行的问题  =.= Orz /**  * HDOJ 1002 A + B Problem II  * Big Numbers Addi

HDOJ3336 Count the string 【KMP前缀数组】+【动态规划】

Count the string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4212    Accepted Submission(s): 1962 Problem Description It is well known that AekdyCoin is good at string problems as well as n

【动态规划】【KMP】HDU 5763 Another Meaning

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5763 题目大意: T组数据,给两个字符串s1,s2(len<=100000),s2可以被解读成2种意思,问s1可以解读成几种意思(mod 1000000007). 题目思路: [动态规划][KMP] 题目有点绕,看看样例就懂了.其实不用KMP直接用substr就能做. 首先不解读成另一个意思的话,f[i]=f[i-1],接着如果当前位置能够与s2匹配,那么f[i]+=f[i-strlen(s2)]

timus.1353. Milliard Vasya&#39;s Function 动态规划

题目传送门 题目大意: 输入一个1到81(9*9)的数字s,求在1到109有多少个数字的数位和等于s. 解题思路: 我们很容易知道一位数字等于s的个数.要使一个i位的数字数位和等于s,可以通过一个i-1位的数字后面加上0~9(如果s<9就是0~s).于是很容易得出方程 dp[i][j]=dp[i-1][j-0]+dp[i-2][j-1]+……+dp[i-9][j-9];其中i表示i位的数字,j表示s.dp[i][j]表示一个i位数字数位和为j的方案数. #include <iostream&g