zoukankan      html  css  js  c++  java
  • POJ2185 Milking Grid [KMP应用]

      一道KMP的好题,可惜数据实在是太弱了。

      给出R*C的字符矩阵,问至少多大面积的小矩阵可以覆盖掉整个大矩阵。很容易想到的解法就是求出循环节然后求最大公倍数,但是这样就忽视了可以不用正好覆盖这个条件,比如aaabaa可以拆成aaab/aa,aaaba/a,aaabaa,而不一定非要拆成4的倍数。正确的做法是求出每一列可能拆分的长度,然后取所有列都可以分的长度中最小的。比如

      abcdeaa
      aaabaaa

      第一个串可以分的长度有5,7,第二个串可以分的长度有4,5,6,7,所以取5作为公共长度。至于怎么求一个字符串所有可以拆分的情况,用KMP处理一遍就可以了,然后从最后一列开始,取i=next[i]直到i=-1,这中间的i-next[i]值都是可取长度,比如aabaabaa,它的next数组是01012345,从最后一列开始,next[8]=5,有8-5=3可取,next[5]=2,有8-2=6可取,next[2]=1,有8-1=7可取,next[1]=0,有8-0=8可取,最终可取的数有3,6,7,8四个数。至于为什么这样做是可行的,想想next数组的性质就知道了,next[i]表示以i结尾的串的前缀和后缀的匹配程度。

      算出宽度后只要将每行的前width个字符作为一个整体,然后KMP求出最小循环节作为height,求出乘积即可。

    #include <stdio.h>
    #include <string.h>
    int r,c;
    char mz[10005][80];
    int ctot[80],next[10005];
    void kmp_next(char *s){
        memset(next,0,5*c);
        next[1]=0,next[0]=-1;
        for(int i=2,j=0;i<=c;i++){
            while(j>0&&s[j+1]!=s[i])j=next[j];
            if(s[j+1]==s[i])j++;
            next[i]=j;
        }
        for(int i=next[c];i!=-1;i=next[i]){
            ctot[c-i]++;
        }
    }
    int kmp_col(){
        memset(next,0,sizeof next);
        next[1]=0;
        for(int i=2,j=0;i<=r;i++){
            while(j>0&&strcmp(mz[j+1]+1,mz[i]+1))j=next[j];
            if(strcmp(mz[j+1]+1,mz[i]+1)==0)j++;
            next[i]=j;
        }
        return r-next[r];
    }
    int solve(){
        memset(ctot,0,sizeof ctot);
        for(int i=1;i<=r;i++){
            kmp_next(mz[i]);
        }
        int width=0;
        for(int i=1;i<=c;i++){
            if(ctot[i]==r){
                width=i;
                break;
            }
        }
        for(int i=1;i<=r;i++){
            mz[i][width+1]='\0';
        }
        return width*kmp_col();
    }
    int main(){
        while(scanf("%d%d",&r,&c)!=EOF){
            for(int i=1;i<=r;i++){
                scanf("%s",mz[i]+1);
            }
            int x=solve();
            printf("%d\n",x);
        }
        return 0;
    }

       

  • 相关阅读:
    SpringCloud Alibaba整合Sentinel
    Jmter入门教程
    惊!!!笔记本外接显示器,显示器界面不能充满全屏
    js-使用attr()方法
    关于JS的assign() 方法
    《转》webpack+vue+vueRouter模块化构建完整项目实例超详细步骤(附截图、代码、入门篇)
    元素水平垂直居中的四种方式(别人文章)
    关于截取字符串substr和substring两者的区别
    JavaScript三种弹出框(alert,confirm和prompt)用法举例
    ::before和::after伪元素的用法
  • 原文地址:https://www.cnblogs.com/swm8023/p/2620853.html
Copyright © 2011-2022 走看看