hdu 1867 求两个串的"和"最小 ,KMP

题意:
      给你两个字符串,让你求str1+str2,就是把1的后面和2的前面重叠的地方只显示一遍就行了 abc + bcd = abcd,要求和的长度最小,和最小的前提下求字典序最小,还有就是两个串可以交换位置的,cdab + abcd = abcdab 而不是 cdabcd,交换位置后合并是最短并且字典序最小的。

 

 

思路:
      首先得到两个next数组,然后用str1 去匹配 str2,再用str2 去匹配str1,(因为可以交换),分别得到子串走到最后时匹配串的位置,x,y,这个位置也就是重合了多少个,如果x == y说明无论谁在前前面,匹配后的长度都是 l1 + l2 - x(或者 l1 + l2 - y ,x 和 y是相等的),这样我们把字典序小的那个放在前面,另一个把前面的x个字母去掉后接到字典序小的那个串的后面。如果x != y,如果x > y 当然是按照大的那个匹配方式输出了。因为要求的是和的长度最小。

 

#include<stdio.h>
#include<string.h>

#define N 100000 + 100

int next_a[N] ,next_b[N];
char str_a[N] ,str_b[N];

void get_next(char str[] ,int next[])
{
    int j ,k ,m;
    m = strlen(str);
    j = 0 ,k = -1;
    next[0] = -1;
    while(j < m)
    {
        if(k == -1 || str[j] == str[k])
        next[++j] = ++k;
        else
        k = next[k];
     }
     return;
}
       
int KMP(char str1[] ,char str2[] ,int next[])
{
    int n ,m ,i ,j;
    n = strlen(str1);
    m = strlen(str2);
    for(i = j = 0 ;i < n ;)
    {
        if(str1[i] == str2[j])
        {
           i ++ ,j ++;
        }
        else
        {
            j = next[j];
            if(j == -1)
            {
                j = 0;
                i ++;
            }
        }
     }
     return j;
}

int main ()
{
    while(~scanf("%s %s" ,str_a ,str_b))
    {
        get_next(str_a ,next_a);
        get_next(str_b ,next_b);
        int x = KMP(str_a ,str_b ,next_b);
        int y = KMP(str_b ,str_a ,next_a);
        if(x == y)
        {
             if(strcmp(str_a ,str_b) <= 0)
             printf("%s%s " ,str_a ,str_b + x);
             else
             printf("%s%s " ,str_b ,str_a + x);
         }
         else
         {
             if(x > y)
             printf("%s%s " ,str_a ,str_b + x);
             else
             printf("%s%s " ,str_b ,str_a + y);
         }
    }
    return 0;
}
       
    

原文地址:https://www.cnblogs.com/csnd/p/12063107.html