【大渣】【多维KMP】奶牛阵列

来源:互联网 发布:淘宝如何修改收货地址 编辑:程序博客网 时间:2024/05/16 19:04

奶牛阵列

Time Limit:10000MS  Memory Limit:65536K
Total Submit:26 Accepted:18 
Case Time Limit:1000MS

Description

每天早晨约翰的奶牛都会在挤奶的时候排成阵列,即站成R(1<=R<=10000)行C(1<=C<=75)列的矩阵。我们知道,约翰是奶牛专家,他打算写一本关于喂养奶牛的书,他发现,当奶牛按不同血统标记以后,整个大矩阵就像由很多小矩阵无缝拼接的一样。 

请帮助约翰找到面积最小的模型矩阵,使他能拼出整个大矩阵,当然,模型矩阵的尺寸不一定能整除大矩阵,也就是说你可以用若干个模型矩阵,拼出一个包含大矩阵的更大的矩阵。

Input

第一行, 两个整数R和C 
接下来是由大写字母构成的R*C的矩阵

Output

一个整数,表示最小模型矩阵的面积。

Sample Input

2 5ABABABABAB

Sample Output

4

Hint

样例说明: 
模型矩阵如下: 
AB 
BA 
拼出的大矩阵如下: 
ABABAB 
BABABA 

Source

usaco 2003 fall Milking Grid

=============================================================================================

分析:

      开始拿到这道题的时候我也没什么思路,就想着写暴力骗点分,因为根本没复习,然后看了第3天我还是觉得想

这道比较好写。于是我就去翻了下KMP的讲义,然后发现一个很牛逼的结论:

Fail[]的性质:

1.如果Len%(Len-Fail[len-1])==0则字符串中必存在最小循环节

2.该循环节长度为Len-Fail[len-1]

3.循环次数为Len/(Len-Fail[len-1])

但是这道题是二维的,感觉这个结论还是没啥用= =

然后我就看样例

ABABAB   此时的矩阵为: AB

BABABA                             BA

他的规模是2*2,然后我就惊奇的发现2是行的最小循环结,也是列的最小循环结(现在看来貌似很明显= =)

然后我就想把它行的循环结*列的循环结不就是答案了么

再来看组数据吧:

我们将每一行看成一个字符

ABAA         '#'

ABAA  -->   '#'  -->所以此时的行的循环结长度为1  -->旋转下,再求一次,就得到列的循环结

ABAA          '#'

ABAA          '#'


          -->ABAB-->A   -->此时的最小的循环结长度为3  -->最终得到的是1×3的矩阵ABA

                            B

                            A

                            B


==============================================================================================

放代码:

#include<cstdio>#include<cstring>#include<iostream>#include<cstdlib>#define maxn 10005using namespace std;char T[maxn][80],rT[80][maxn];int Fail[maxn];void _get_x(int l) {int j=-1;Fail[0]=-1;for (int i=1;i<l;i++) {while(j>-1&&strcmp(T[j+1],T[i]))j=Fail[j];if(!strcmp(T[j+1],T[i]))j++;Fail[i]=j;}}void _rotate(int x,int y) {for(int i=0;i<y;i++) {for(int j=0;j<x;j++)rT[i][j]=T[j][i];rT[i][x]='\0';}}void _get_y(int l) {int j=-1;Fail[0]=-1;for(int i=1;i<l;i++) {while(j>-1&&strcmp(rT[j+1],rT[i]))j=Fail[j];if(!strcmp(rT[j+1],rT[i]))j++;Fail[i]=j;}}int main() {//freopen("grid.in","r",stdin);//freopen("grid.out","w",stdout);int x,y;    scanf("%d%d",&x,&y);for(int i=0;i<x;i++)scanf("%s",T[i]);_get_x(x);//求行的Fail[]//for(int i=0;i<x;i++)cout<<Fail[i]<<" ";//putchar(10);int ans=x-Fail[x-1]-1;//行的最小循环结_rotate(ans,y);//旋转矩阵_get_y(y);//求列的Fail[]//for(int i=0;i<y;i++)cout<<Fail[i]<<" ";        //putchar(10);ans=ans*(y-Fail[y-1]-1);//列的循环结printf("%d\n",ans);return 0;}


0 0