poj2185 Milking Grid(二维KMP+最小覆盖矩阵)

来源:互联网 发布:淘宝如何设置分享有赏 编辑:程序博客网 时间:2024/05/21 19:26

题意:在字符矩阵中找出一个最小子矩阵,使其多次复制所得的矩阵包含原矩阵。首先我们计算答案矩阵的列数,叫做宽。对每行都计算出所有的重复子串可能的长度,如:AAAABAAA,可能的重复子串长度为:5,6,7,8.如何计算呢?k从m开始,每次k-fail[k]即为重复子串长度,k=fail[k],直到k=0.每行中都出现过的最小长度即为答案矩阵的宽。(遇到一个可能长度就计数器+1,最后从小到大扫一遍,次数为n的即可)。然后我们要计算答案矩阵的行数。那么就把每一行长度为答案矩阵的宽的前缀取出来作为一个单位,进行二维kmp(每次比较一个字符串。)其实和一维一模一样hh。。然后这样的最小重复子串长度就是答案矩阵的行数。


#include <cstdio>#include <cstring>#define N 10010int n,m,fail[N],f[80];char s[N][80];inline void getfail(char *t){int k=0;fail[1]=0;for(int i=2;i<=m;++i){while(k&&t[k+1]!=t[i]) k=fail[k];if(t[k+1]==t[i]) ++k;fail[i]=k;}}int main(){//freopen("a.in","r",stdin);scanf("%d%d",&n,&m);for(int i=1;i<=n;++i) scanf("%s",s[i]+1);for(int i=1;i<=n;++i){getfail(s[i]);for(int k=m;k;k=fail[k]) f[m-fail[k]]++;}for(int i=1;i<=m;++i) if(f[i]==n) m=i;for(int i=1;i<=n;++i) s[i][m+1]=0;int k=0;fail[1]=0;for(int i=2;i<=n;++i){while(k&&strcmp(s[k+1]+1,s[i]+1)) k=fail[k];if(strcmp(s[k+1]+1,s[i]+1)==0) ++k;fail[i]=k;}printf("%d\n",m*(n-fail[n]));return 0;}