HDU 4300Clairewd’s message 扩展kmp || kmp

来源:互联网 发布:淘宝几天可以申请售后 编辑:程序博客网 时间:2024/05/07 09:25

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4300

题意:有一段字符串由密文和明文组成,密文是完好的,明文可能是残缺的。首先给出密文转换表,然后给出密文明文字符串,然后复原出最短的密文明文字符串(补上明文)

思路:可以用扩展kmp求解。首先,明文的起始位置一定在字符串后半段(密文 >= 明文),于是把前半段转换成明文,然后用扩展kmp求每一个位置和字符串的最长公共前缀长度,后半段中满足next[i] + i = len的i,一定是明文的起始位置,因为这代表从i开始以后完全重合与字符串首部的一段字符。注意明文可能完全丢失

扩展kmp

#include <iostream>#include <algorithm>#include <cstdio>#include <queue>#include <map>#include <vector>#include <cstring>#include <cmath>#include <set>using namespace std;const int N = 100010;int nt[N];char s1[100], s2[N], s3[N], tab[100];void getnt(char s[]){    int p = 0, len = strlen(s);    nt[0] = len;    while(p + 1 < len && s[p] == s[p+1]) p++;    nt[1] = p;    int k = 1;    for(int i = 2; i < len; i++)    {        if(nt[i-k] + i < nt[k] + k)            nt[i] = nt[i-k];        else        {            int j = nt[k] + k - i;            if(j < 0) j = 0;            while(i + j < len && s[i+j] == s[j]) j++;            nt[i] = j;            k = i;        }    }}int main(){    int t;    scanf("%d", &t);    while(t--)    {        scanf("%s%s", s1, s2);        int len = strlen(s2);        for(int i = 0; i < 26; i++)            tab[s1[i]-'a'] = i + 'a'; //密文字符对应的明文字符        for(int i = 0; i < (len + 1) / 2; i++)            s3[i] = tab[s2[i]-'a']; //密文转明文        for(int i = (len + 1) / 2; i <= len; i++)            s3[i] = s2[i];        getnt(s3);        int res = len; //当找不到公共前缀时,意味整个串都是密文,所以预先给res赋值为len        for(int i = (len + 1) / 2; i < len; i++)            if(nt[i] + i == len) //条件成立说明从i位置开始到末尾是字符串的前缀,认为从i开始是明文            {                res = i;                break;            }        printf("%s", s2);        for(int i = len - res; i < res; i++)            printf("%c", tab[s2[i]-'a']);        printf("\n");    }    return 0;}

kmp做法。思路也是求后半段中和字符串的最长公共前缀长度

#include <iostream>#include <algorithm>#include <cstdio>#include <queue>#include <map>#include <vector>#include <cstring>#include <cmath>#include <set>using namespace std;const int N = 100100;int nt[N];char s1[100], tab[100], s2[N], s3[N];void getnt(char s[]){    int i = 0, j = -1;    nt[0] = -1;    while(s[i])    {        if(j == -1 || s[i] == s[j])        {            i++, j++;            if(s[i] != s[j]) nt[i] = j;            else nt[i] = nt[j];        }        else j = nt[j];    }}int kmp(char s1[], char s2[], int len){    getnt(s2);    int i = (len + 1) / 2, j = 0;    while(s1[i])    {        if(j == -1 || s1[i] == s2[j])            i++, j++;        else j = nt[j];    }    return j;}int main(){    int t;    scanf("%d", &t);    while(t--)    {        scanf("%s%s", s1, s2);        int len = strlen(s2);        for(int i = 0; i < 26; i++)            tab[s1[i]-'a'] = i + 'a';        for(int i = 0; i < (len + 1) / 2; i++)            s3[i] = tab[s2[i]-'a'];        for(int i = (len + 1) / 2; i <= len; i++)            s3[i] = s2[i];        int res = kmp(s2, s3, len);        printf("%s", s2);        for(int i = res; i < len - res; i++)            printf("%c", tab[s2[i]-'a']);        printf("\n");    }    return 0;}



0 0
原创粉丝点击