Milking Grid
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 9401 | Accepted: 4096 |
Description
Every morning when they are milked, the Farmer John's cows form a rectangular grid that is R (1 <= R <= 10,000) rows by C (1 <= C <= 75) columns. As we all know, Farmer John is quite the expert on cow behavior, and is currently writing a book about feeding behavior in cows. He notices that if each cow is labeled with an uppercase letter indicating its breed, the two-dimensional pattern formed by his cows during milking sometimes seems to be made from smaller repeating rectangular patterns.
Help FJ find the rectangular unit of smallest area that can be repetitively tiled to make up the entire milking grid. Note that the dimensions of the small rectangular unit do not necessarily need to divide evenly the dimensions of the entire milking grid, as indicated in the sample input below.
Help FJ find the rectangular unit of smallest area that can be repetitively tiled to make up the entire milking grid. Note that the dimensions of the small rectangular unit do not necessarily need to divide evenly the dimensions of the entire milking grid, as indicated in the sample input below.
Input
* Line 1: Two space-separated integers: R and C
* Lines 2..R+1: The grid that the cows form, with an uppercase letter denoting each cow's breed. Each of the R input lines has C characters with no space or other intervening character.
* Lines 2..R+1: The grid that the cows form, with an uppercase letter denoting each cow's breed. Each of the R input lines has C characters with no space or other intervening character.
Output
* Line 1: The area of the smallest unit from which the grid is formed
Sample Input
2 5 ABABA ABABA
Sample Output
2
Hint
The entire milking grid can be constructed from repetitions of the pattern 'AB'.
Source
首先在这里说下,本题的每个单个的步骤的思路可以参考Poj1961 Period最小循环元
这道题。
题目分析:看题目可以发现本题不存在输出无循环子矩阵这种情况,或必须大于1这种条件,所以不同于以上那道题,无论多小(多大)都应按照解法解出来。题目我感觉原文解释的也不是很清楚,但意思就是找到最小循环元,只不过这里的循环元是子矩阵。
算法分析:
- 暴力解法:本题暴力我觉得更难写,如果不用KMP中next数组的性质的话,需要考虑的事情太多了。
- KMP过本题的解法:对于每一行,都可以求出它的最小循环元(这里的循环元就是线性的了,而且注意这里的最小只能保证这一行)。而为了保证整个矩阵,所以应该在每一行最小的值中取最大的。对于每一列,用同样的方法。最后,要得到这个子矩阵的大小,长乘宽就行了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char str[10010][80]/*next_[10010]*/;
int n,m,next_[10010];
inline int Getrow_Next(int row)
{
next_[1]=0;
for(int i=2,j=0;i<=m;i++)
{
while(j>0&&str[row][i]!=str[row][j+1])j=next_[j];
if(str[row][i]==str[row][j+1])
j++;
next_[i]=j;
}
/*int p=1;
for(int i=2;i<=m;i++)
if(i%(i-next_[i])==0&&i/(i-next_[i])>1)
ans[p++]=i/(i-next_[i]);
p-=2;
while(ans[p]!=0&&p>1)p--;
return ans[p];*/
return m-next_[m];
}
inline int Getcol_Next(int col)
{
next_[1]=0;
for(int i=2,j=0;i<=n;i++)
{
while(j>0&&str[i][col]!=str[j+1][col])j=next_[j];
if(str[i][col]==str[j+1][col])
j++;
next_[i]=j;
}
/*int p=1;
for(int i=2;i<=n;i++)
if(i%(i-next_[i])==0&&i/(i-next_[i])>1)
ans[p++]=i/(i-next_[i]);
p-=2;
while(ans[p]!=0&&p>1)p--;
return ans[p];*/
return n-next_[n];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",str[i]+1);
int minr=0,minc=0;
for(int i=1;i<=n;i++)
{
int ans1 = Getrow_Next(i);
minr=max(minr,ans1);
}
for(int i=1;i<=m;i++)
{
int ans2 = Getcol_Next(i);
minc=max(minc,ans2);
}
printf("%d\n",minc*minr);
return 0;
}
代码中注释部分:之前考虑完全按照Period那道题想了,不过这道题中n-next[n]直接就是整个行(列)需要的最小循环元(如果next数组不能从前面获得更新,那就需要n-0也就是整个行,即为一整个行循环某个前缀得不到),而并不用考虑前缀中的每一个最小循环元。这也说明了题目分析里的:可能会出现循环得不到整个矩阵,答案就成了整个矩阵的大小。