zoukankan      html  css  js  c++  java
  • hdu 1867 A + B for you again

    Generally speaking, there are a lot of problems about strings processing. Now you encounter another such problem. If you get two strings, such as “asdf” and “sdfg”, the result of the addition between them is “asdfg”, for “sdf” is the tail substring of “asdf” and the head substring of the “sdfg” . However, the result comes as “asdfghjk”, when you have to add “asdf” and “ghjk” and guarantee the shortest string first, then the minimum lexicographic second, the same rules for other additions.

    InputFor each case, there are two strings (the chars selected just form ‘a’ to ‘z’) for you, and each length of theirs won’t exceed 10^5 and won’t be empty.OutputPrint the ultimate string by the book.Sample Input
    asdf sdfg
    asdf ghjk
    Sample Output
    asdfg
    asdfghjk

    合并字符串,两串a,b,a的后缀和b的前缀最大匹配长度为d,b的后缀和a的前缀的最大匹配长度为e,哪个长度大,就怎么衔接,否则按字母顺序衔接。
    kmp找两个长度。
    代码:
    #include <stdio.h>
    #include <string.h>
    #define MAX 100005
    char a[MAX],b[MAX];
    int Next[MAX];
    void getNext(int n,char *s) {
        int i = 0,j = -1;
        Next[i] = -1;
        while(i < n) {
            if(j == -1 || s[j] == s[i]) {
                Next[++ i] = ++ j;
            }
            else j = Next[j];
        }
    }
    int kmp(char *p,char *q) {
        int n = strlen(p),m = strlen(q);
        getNext(m,q);
        int i = -1,j = -1;
        while(i < n) {
            if(j == -1 || p[i] == q[j]) {
                i ++;j ++;
            }
            else j = Next[j];
        }
        return j;
    }
    int main() {
        while(~scanf("%s%s",a,b)) {
            int d = kmp(a,b),e = kmp(b,a);///保存a后缀和b前缀的最大重叠 以及 反过来 比较哪个大 就重叠那个 按相应顺序输出,如果相等就按字典序
            if(d > e) printf("%s%s",a,b + d);
            else if(d < e) printf("%s%s",b,a + e);
            else {
                if(strcmp(a,b) > 0)printf("%s%s",b,a + e);
                else printf("%s%s",a,b + d);
            }
            putchar('
    ');
        }
    }

    也可以组合求Next。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define MAX 100005
    using namespace std;
    char a[MAX],b[MAX],s[MAX * 2];
    int Next[MAX * 2],m;
    int getNext(char *p,char *q) {
        strcpy(s,p);
        strcat(s,q);
        int i = 0,j = -1;
        Next[i] = -1;
        while(s[i]) {
            if(j == -1 || s[j] == s[i]) {
                Next[++ i] = ++ j;
            }
            else j = Next[j];
        }
        int  c = strlen(s);
        while(Next[c] > m) c = Next[c];
        return Next[c];
    }
    int main() {
        while(~scanf("%s%s",a,b)) {
            m = min(strlen(a),strlen(b));
            int d = getNext(b,a),e = getNext(a,b);///保存a后缀和b前缀的最大重叠 以及 反过来 比较哪个大 就重叠那个 按相应顺序输出,如果相等就按字典序
            if(d > e) printf("%s%s",a,b + d);
            else if(d < e) printf("%s%s",b,a + e);
            else {
                if(strcmp(a,b) > 0)printf("%s%s",b,a + e);
                else printf("%s%s",a,b + d);
            }
            putchar('
    ');
        }
    }

    当然 也可以用扩展kmp

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define MAX 100005
    using namespace std;
    char a[MAX],b[MAX];
    int Next[MAX],Prefix[MAX];
    void getNext(char *str) {///获得Next数组
        int p = 1;///匹配最远的开始匹配位置 比如从i开始和0位置依次往后匹配相等能到最远的位置 p就是i 即i + Next[i] - 1最大时的i为p
        Next[0] = strlen(str);///显然自己和自己匹配
        Next[1] = 0;
        while(str[Next[1] + 1] && str[Next[1] + 1] == str[Next[1]]) Next[1] ++;///匹配1位置作为基础
        for(int i = 2;str[i];i ++) {///2位置开始
            if(i + Next[i - p] < p + Next[p]) Next[i] = Next[i - p];///如果不超过最远位置
            else {///超过最远位置
                if(p + Next[p] - 1 >= i) Next[i] = p + Next[p] - i;///i点没超过最远位置 实际是 p + Next[p] - 1 - i + 1
                else Next[i] = 0;///否则从头开始匹配啊
                while(str[Next[i] + i] && str[Next[i]] == str[Next[i] + i]) Next[i] ++;///继续匹配
                p = i;
            }
        }
    }
    int ExKmp(char *str1,char *str2) {
        getNext(str2);
        int p = 0,len = strlen(str1);
        Prefix[0] = 0;
        while(str1[Prefix[0]] && str2[Prefix[0]] && str1[Prefix[0]] == str2[Prefix[0]]) Prefix[0] ++;
        for(int i = 1;str1[i];i ++) {
            if(i + Next[i - p] < p + Prefix[p]) Prefix[i] = Next[i - p];///i加上i-p前缀长度 没超过最远位置
            else {
                if(i <= p + Prefix[p] - 1) Prefix[i] = p + Prefix[p] - i;///i没超过最远位置
                else Prefix[i] = 0;
                while(str1[i + Prefix[i]] && str1[i + Prefix[i]] == str2[Prefix[i]]) Prefix[i] ++;///继续匹配
                p = i;///更新最远位置下标
            }
        }
        for(int i = 0;i < len;i ++) {
            if(i + Prefix[i] == len) return Prefix[i];
        }
        return 0;
    }
    int main() {
        while(~scanf("%s%s",a,b)) {
            int d = ExKmp(a,b),e = ExKmp(b,a);///保存a后缀和b前缀的最大重叠 以及 反过来 比较哪个大 就重叠那个 按相应顺序输出,如果相等就按字典序
            if(d > e) printf("%s%s",a,b + d);
            else if(d < e) printf("%s%s",b,a + e);
            else {
                if(strcmp(a,b) > 0)printf("%s%s",b,a + e);
                else printf("%s%s",a,b + d);
            }
            putchar('
    ');
        }
    }

     再次复习扩展kmp

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define MAX 100005
    using namespace std;
    
    void getNext(char *str,int *Next) {
        int p = 1;
        while(str[1 + Next[1]] && str[1 + Next[1]] == str[Next[1]]) Next[1] ++;
        for(int i = 2;str[i];i ++) {
            if(i + Next[i - p] < p + Next[p]) Next[i] = Next[i - p];
            else {
                if(i <= p + Next[p] - 1) Next[i] = p + Next[p] - i;
                else Next[i] = 0;
                while(str[i + Next[i]] && str[i + Next[i]] == str[Next[i]]) Next[i] ++;
                p = i;
            }
        }
    }
    int ExKmp(char *s,char *t) {
        int Next[MAX] = {0},Prefix[MAX] = {0};
        getNext(t,Next);
        int p = 0;
        while(s[0 + Prefix[0]] && s[0 + Prefix[0]] == t[Prefix[0]]) Prefix[0] ++;
        for(int i = 1;s[i];i ++) {
            if(i + Next[i - p] < p + Prefix[p]) Prefix[i] = Next[i - p];
            else {
                if(i < p + Prefix[p]) Prefix[i] = p + Prefix[p] - i;
                else Prefix[i] = 0;
                while(s[i + Prefix[i]] && s[i + Prefix[i]] == t[Prefix[i]]) Prefix[i] ++;
                if(i + Prefix[i] > p + Prefix[p]) p = i;///不加这一步 最后返回的就不对,  比如 aaaa aaa 应输出 aaaa
            }
        }
        return p + Prefix[p] < strlen(s) ? 0 : Prefix[p];
    }
    int main() {
        char a[MAX],b[MAX];
        while(~scanf("%s%s",a,b)) {
            int d = ExKmp(a,b),e = ExKmp(b,a);
            if(d > e) printf("%s%s",a,b + d);
            else if(d < e) printf("%s%s",b,a + e);
            else {
                if(strcmp(a,b) > 0)printf("%s%s",b,a + e);
                else printf("%s%s",a,b + d);
            }
            putchar('
    ');
        }
    }
  • 相关阅读:
    从获取QQ验证码谈如何改进用户体验,提高程序的响应效果
    如何利用C#批量注册QQ邮箱
    利用DotRAS组件,实现ADSL的自动拨号断网自动化操作
    探讨如何利用C#登录QQ邮箱进行群邮件的发送
    利用C#开发基于snmpsharpnet基础的SNMP开发应用
    QQ窗口抓取及如何进行自动化操作
    对比三种GoogleMap图标操作处理,谈如何构造快速响应的GoogleMap图标叠加操作
    Winform下的地图开发控件(GMap.NET)使用心得之三批量解析地址经纬度坐标
    基于Lumisoft.NET实现的邮件发送功能
    谈谈数据加密的处理提供各种算法处理
  • 原文地址:https://www.cnblogs.com/8023spz/p/7795862.html
Copyright © 2011-2022 走看看