poj 2185(二维kmp)

题意:让你求一个最小的覆盖子矩阵。

分析:首先第一点是确定的:那就是这个子矩阵肯定位于左上角,然后按行考虑,求出每一行可能的重复子串的长度,然后取所有行都存在并且长度最短的长度最为最小子矩阵的宽,

最后按列队长度为宽的字符串进行一次kmp求出循环节的长度。

代码实现:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,windth,height;
char str[10005][80];
int visited[80],next[10005];

void solve()
{
    int i,j;
    for(i=0;i<n;i++)
      str[i][windth]='\0';
    i=0;j=-1;next[0]=-1;
    while(i<n)//按列进行kmp求出最小子矩阵的高
    {
        if(j==-1||strcmp(str[i],str[j])==0)
        {
            i++;j++;
            next[i]=j;
        }
        else
            j=next[j];
    }
    height=n-next[n];
    printf("%d\n",windth*height);
}

int main()
{
    int i,j;
    int x,y;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        getchar();
        memset(visited,0,sizeof(visited));
        for(i=0;i<n;i++)//求出每一行都有的最小重复子串作为宽
        {
            scanf("%s",str[i]);
            for(j=m;j>=1;j--)
            {
                x=0;y=0;
                for(;str[i][x]!='\0';x++,y++)
                {
                    if(y==j)
                     y=0;
                    if(str[i][x]!=str[i][y])
                     break;
                }
                if(str[i][x]=='\0')
                 visited[j]++;
            }
        }
        for(i=1;i<=m;i++)
         if(visited[i]==n)
          break;
        windth=i;
        solve();
    }
    return 0;
}

 

posted on 2013-09-16 20:32  后端bug开发工程师  阅读(302)  评论(0编辑  收藏  举报

导航