zoukankan      html  css  js  c++  java
  • Match:Cyclic Nacklace(KMP的next数组的高级应用)(HDU 3746)

                     

                      串珠子

      题目大意:给定一个字串,要你找到如果要使之成为循环串,在末尾需要的最小的字数(只能添加字符,不能删减字符)

      首先联动一下之前做过的动态规划问题POJ 3280,当然了3280这一题是用的LD,因为他可以添加或者删除(加上修改也行,但是要改状态方程了)

      而我们现在要讨论的这一题(HDU 3746)是有限制的,首先它只能添加不能删除,其次一定是要在末尾添加。

      其实这样的题用kmp可以很快地解决,其实这样的题目是循环节的题目,之前我已经写过很多了,这一题是对循环节的深刻理解。

      首先我们我们明白,对于kmp算法的next数组,如果一个字串是循环字串,那么他一定有len%(len-next[len])==0且next[len]>0,这个已经从1961等题论证了

      现在我们就是要搞清楚,如果len%(len-next[len])!=0会如何,我们先来看一个例子

      

      比如上个例子,他的最大前缀和后缀是abcdeabcd,如果要在末尾加上字符使他循环,那么一定是要加上e,使新的循环节是abcde,而abcde的长度刚好是len-next[len]

      

      再如这个例子,最大前缀和后缀是abcabcab,末尾加上c循环节就是abc,刚好也是len-next[len]

      

      对于这个,不存在最大前后缀,必须加上len才能使之成为循环字串,而next[len]刚好是0,也符合len-next[len]

      那么我们是不是能下结论,无论对于什么字串,无论是否循环,最小的循环节一定是len-next[len]呢?答案是最小循环节一定满足这个结论

      我们再来看第二组

      我们把最大前后缀对齐,发现突出的部分的长度就是新的数组的循环节的长度,事实上,我们将任何数组按照这个方式对齐都有这个结论,就是突出的长度刚好是新的数组的循环节的长度,而这个长度刚好就是len-next[len](非严格证明),那么原数组按照新的循环节划分会剩下len%(len-next[len])个单元(注意len-next[len]要特判,因为可能会存在len-next[len]==0),接着我们就可以直接用len-len%(len-next[len])得到需要补齐的长度了,这就是循环节题目的一般做法。  

      参考:http://blog.csdn.net/u013480600/article/details/22954037

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <functional>
     4 #include <string.h>
     5 
     6 using namespace std;
     7 
     8 static char input[100010];
     9 static int _Next[100010];
    10 
    11 void Get_Next(const int);
    12 
    13 int main(void)
    14 {
    15     int case_sum, len;
    16     scanf("%d", &case_sum);
    17 
    18     while (case_sum--)
    19     {
    20         scanf("%s", input);
    21         len = strlen(input);
    22         Get_Next(len);
    23 
    24         if (_Next[len] == 0)//不存在循环节
    25             printf("%d
    ", len);
    26         else if (len % (len - _Next[len]) == 0)//已经是循环节了
    27             printf("0
    ");
    28         else
    29             printf("%d
    ", len - _Next[len] - len % (len - _Next[len]));
    30     }
    31     return EXIT_SUCCESS;
    32 }
    33 
    34 void Get_Next(const int len)
    35 {
    36     int i = 0, k = -1;
    37     _Next[0] = -1;
    38 
    39     while (i < len)
    40     {
    41         if (k == -1 || input[i] == input[k])
    42         {
    43             i++;
    44             k++;
    45             _Next[i] = k;
    46         }
    47         else k = _Next[k];
    48     }
    49 }

      

  • 相关阅读:
    上一张作业day16
    python 函数递归,三元表达式解读,匿名一次性函数,模块略解
    迭代器,生成器与内置函数
    闭合函数和装饰器
    函数的其他关键点*与**,函数的对象可以当做变量去使用,函数的嵌套,名称空间
    python函数,应用与讲解
    文件处理方式
    html-04 html骨架
    html-03 Web标准
    html-02 浏览器内核
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/5183264.html
Copyright © 2011-2022 走看看