zoukankan      html  css  js  c++  java
  • Manacher 算法(hdu 3068 && hdu 3294)

      今天打算补前晚 BC 的第二题,发现要用到能在 O(n) 时间求最大回文子串长度的 Manacher 算法,第一次听,于是便去百度了下,看了大半天,总算能看懂了其思想,至于他给出的代码模板我没能完全看懂,只好自己试着实现,发现理解了思想后还是能实现出来的,用自己的风格去写更好理解,先附上讲解 Manacher 算法的几个链接:

      Manacher算法--O(n)回文子串算法 (我就是看这个理解的~)

      Manacher算法处理字符串回文

      hdu3068之manacher算法+详解

      浅谈manacher算法

      hdu 3068 正好是裸题,我便试着写下,我是这样子构造新串的:

      hdu 3068 代码如下:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N = 110005;
     6 
     7 // str 为原串, s 为新串
     8 char str[N], s[N << 1];
     9 int p[N << 1];
    10 // p[i] 表示以 s[i] 为中心时的回文半径,不包括 p[i]
    11 // 即若 s[i - 1] != s[i + 1] 时,p[i] = 0;
    12 
    13 int main() {
    14     while(~scanf("%s",str)) {
    15         int n = strlen(str);
    16         s[0] = '$';             // 构造新串
    17         s[1] = '#';
    18         for(int i = 0; i < n; ++i) {
    19             s[i * 2 + 2] = str[i];      // 下标要处理好
    20             s[i * 2 + 3] = '#';
    21         }
    22         n = n * 2 + 2;             // 更新新串的长度
    23         s[n] = '';               // 最后的结束符别忘了
    24 
    25         // right 记录的是在 i 之前的回文串中,某个回文串延伸至最右端的位置
    26         // id 就是该回文串的下标(注意都是在新串中的)
    27         int right = 0, id = 0;
    28         p[0] = 0;
    29         // 因为是 s[0] == '$',作为特殊标记,左右两边都没有相等的,所以初始化为 0,
    30         // 同理 right 一开始能延伸到的位置就是 s[0] 的位置,也就是 0,id 当然也为 0
    31 
    32         // 主算法要开始了
    33         for(int i = 1; i < n; ++i) {
    34             if(right > i)
    35                 p[i] = min(p[2 * id - i], right - i);
    36             else    p[i] = 0;
    37             while(s[i + p[i] + 1] == s[i - p[i] - 1])   ++p[i];
    38             if(i + p[i] > right) {
    39                 right = i + p[i];
    40                 id = i;
    41             }
    42         }
    43 
    44 //        printf("
    下标: ");
    45 //        for(int i = 0; i <= n; ++i)
    46 //            printf("%d  ",i);
    47 //        puts("");
    48 //        printf("新串: ");
    49 //        for(int i = 0; i < n; ++i)
    50 //            printf("%c  ",s[i]);
    51 //        printf(" \0
    p[i]: ");
    52 //        for(int i = 0; i < n; ++i)
    53 //            printf("%d  ",p[i]);
    54 //        puts("");
    55 
    56         int ans = 0;
    57         for(int i = 1; i < n; ++i)
    58             ans = max(ans, p[i]);       // p[i] 就是原串中的回文长度, 无须作任何 +1、-1
    59         printf("%d
    ",ans);
    60     }
    61     return 0;
    62 }
    View Code

      还有一题也是需要用到这个算法的,hdu 3294,只是对于最后的结果输出需要处理一下,恶心的模拟,直接贴代码了:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N = 200005;
     6 
     7 char str[N], s[N << 1];
     8 int p[N << 1];
     9 
    10 int main() {
    11     while(gets(str)) {
    12         int n = strlen(str);
    13         s[0] = '$';
    14         s[1] = '#';
    15         for(int i = 2; i < n; ++i) {
    16             s[i * 2 - 2] = str[i];
    17             s[i * 2 - 1] = '#';
    18         }
    19         n = n * 2 - 2;
    20         s[n] = '';
    21 
    22         int right = 0, id = 0;
    23         p[0] = 0;
    24         for(int i = 1; i < n; ++i) {
    25             if(right > i)
    26                 p[i] = min(p[id * 2 - i], right - i);
    27             else    p[i] = 0;
    28             while(s[i + p[i] + 1] == s[i - p[i] - 1])   ++p[i];
    29             if(i + p[i] > right) {
    30                 right = i + p[i];
    31                 id = i;
    32             }
    33         }
    34         int Max = 0, mid;
    35         for(int i = 1; i < n; ++i) {
    36             if(p[i] > Max) {
    37                 Max = p[i];
    38                 mid = i;
    39             }
    40         }
    41         if(Max == 1) {
    42             puts("No solution!");
    43             continue;
    44         }
    45 
    46         int strid = (mid - Max + 1) / 2 + 1;
    47         printf("%d %d
    ", strid - 2, strid - 2 + Max - 1);
    48 
    49         for(int i = 0; i < Max; ++i) {
    50             char ch = str[strid + i] + ('a'- str[0]);
    51             if(ch < 'a')   ch = 'z' + 1 - ('a' - ch);
    52             else if(ch > 'z')   ch = 'a' - 1 + (ch - 'z');
    53             printf("%c",ch);
    54         }
    55         puts("");
    56     }
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    Oracle+PL+SQL从入门到精通.丁士锋.清华大学出版社.2012
    《 Oracle查询优化改写 技巧与案例 》电子工业出版社
    HTML5从入门到精通(明日科技) 中文pdf扫描版
    《JavaWeb从入门到精通》(明日科技,清华大学出版社)
    JavaScript从入门到精通(附光盘1张):作者:明日科技出版社:清华大学出版社出版时间:2012年09月
    ORACLE_修改实例的内存大小
    JAVA图书管理系统汇总共27个
    IntelliJ Idea 2017 免费激活方法
    spring springMvc spring-boot spring-cloud分别是什么
    nodejs环境 + 入门 + 博客搭建
  • 原文地址:https://www.cnblogs.com/Newdawn/p/4700093.html
Copyright © 2011-2022 走看看