Milking Grid
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 4804 | Accepted: 1999 |
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'.
支持他们的观点:最小重复矩阵一定靠左上角。
第一步也是找最小重复子矩阵的宽,网上的大部分代码就卡在这里,如实例(poj讨论数据):
实例1:
2 8
ABCDEFAB
AAAABAAA
实例2:
2 8
ABCDEFAB
AAAABABC
误区1:网上的代码找宽的方法(多数代码):用KMP的next求出每行最小重复子串长度,然后求这些长度的公倍数,对于这个实例:第一行为6,第二行为5,6与5的最小公倍数为30,大于8则取8为宽,这种思路对实例2很合适,但明显对于实例1是错误的。(这种思路的AC代码网上有非常多)
误区2:同样用KMP的next求出每行最小重复子串长度,然后取最大的那个长度作为宽,这种对于实例1来说刚好能过,但对于实例2就无能为力了。(这种思路的AC代码网上有比较少)
出现以上误区的博文误倒大家,只能说明POJ数据太弱。
说说我的思路吧:找出每行的重复子串长度的各种可能情况,然后每行都有的并且是最小长度作为宽width。
第二步找最小重复子矩阵的高,这个思路和网上的差不多,取每行的宽为width的前缀作为一个单位,对这0到r-1个单位求出KMP的next函数,找出最小重复子序列的单位数作为高height,最终答案为width*height。
第一步也是找最小重复子矩阵的宽,网上的大部分代码就卡在这里,如实例(poj讨论数据):
实例1:
2 8
ABCDEFAB
AAAABAAA
实例2:
2 8
ABCDEFAB
AAAABABC
误区1:网上的代码找宽的方法(多数代码):用KMP的next求出每行最小重复子串长度,然后求这些长度的公倍数,对于这个实例:第一行为6,第二行为5,6与5的最小公倍数为30,大于8则取8为宽,这种思路对实例2很合适,但明显对于实例1是错误的。(这种思路的AC代码网上有非常多)
误区2:同样用KMP的next求出每行最小重复子串长度,然后取最大的那个长度作为宽,这种对于实例1来说刚好能过,但对于实例2就无能为力了。(这种思路的AC代码网上有比较少)
出现以上误区的博文误倒大家,只能说明POJ数据太弱。
说说我的思路吧:找出每行的重复子串长度的各种可能情况,然后每行都有的并且是最小长度作为宽width。
第二步找最小重复子矩阵的高,这个思路和网上的差不多,取每行的宽为width的前缀作为一个单位,对这0到r-1个单位求出KMP的next函数,找出最小重复子序列的单位数作为高height,最终答案为width*height。
给出两组数据:
Input 2 8 ABCDEFAB ABCDEABC 2 8 ABCDEFAB AAAABAAA Output 16 12解释下关于len-next[len]为什么是循环周期:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define INF 99999999
using namespace std;
const int MAX=10000+10;
char s[MAX][77];
int rnum[77],next[MAX];
int get_next(int n){
int i=-1,j=0;
next[0]=-1;
while(j<n){
if(i == -1 || strcmp(s[i],s[j]) == 0)next[++j]=++i;//把每一行看成一个字符求next
else i=next[i];
}
return n-next[n];
}
int main(){
int r,w,x,y;
while(cin>>r>>w){
memset(rnum,0,sizeof rnum);
for(int i=0;i<r;++i){
cin>>s[i];
for(int j=1;j<=w;++j){
for(x=0,y=j;y<w;++x,++y){
if(s[i][x%j] != s[i][y])break;//判断是否是循环周期
}
if(y == w)++rnum[j];//统计所有循环周期长度的个数,如aaaaa就有a,aa,aaa,aaaa,aaaaa多个循环周期
}
}//求y也可以和列一样求法,但是比较每一列字符串却比较难,所以用暴力统计(上面是暴利统计)去求
for(y=1;y<=w;++y)if(rnum[y] == r)break;//求所有行共同最小周期y,0~y-1为一个周期
for(int i=0;i<r;++i)s[i][y]='\0';
x=get_next(r);//求0~y列共同最小周期x,0~x-1为一个周期
cout<<x*y<<endl;
}
return 0;
}