题目大意:
每天早上FJ挤奶的牛都会排成一个矩阵,R行C列(1 ≤ R ≤ 10,000,1 ≤ C ≤ 75),FJ在喂奶过程中给牛的行为进行了分类,给不同的牛贴不同的分类标签,标签为一大写字母,然后FJ神奇地发现这个大矩阵是由某个小矩阵重复排列而得的,但是这个大矩阵又不需要严格地均匀分成若干小矩阵(当然也可以)。
现只有一个测例,测例中给出R、C以及由大写字母组成的矩阵,隔行但是没行中没有空格等间隔,要求输出最小循环矩阵的面积。
注释代码:
/*
* Problem ID : POJ 2185 Milking Grid
* Author : Lirx.t.Una
* Language : G++
* Run Time : 16 ms
* Run Memory : 1168 KB
*/
#pragma G++ optimize("O2")
#include <string.h>
#include <stdio.h>
//对于最小循环矩阵的求法
//可以将每一行看做一个字符,对行组成的字符串求最小循环节的长度
//并将每一列也看做一个字符,对每列组成的字符串求最小循环节的长度
//最终最小循环矩阵的面积就是以上两个值相乘的结果
//比较的时候用字符串比较函数来模拟两个字符的等值判断
//对于一列组成的字符串之间的等值判断需要自己写函数来模拟strcmp!!
#define TRUE 1
#define FALSE 0
//maximum row length
#define MAXR 10002
//maximum column length
#define MAXC 77
typedef int BOOL;
char g[MAXR][MAXC];//grid,网格,存放字符矩阵
int nxt[MAXR];//next数组
int r, c;//行长和列长
BOOL
eq( int x, int y ) {//equal
//比较两个列所表示的字符串
//x、y分别表示比较列的列序号
int i;
for ( i = 1; i <= r; i++ )
if ( g[i][x] != g[i][y] )
return FALSE;
return TRUE;
}
int
rkmp(void) {//row_KMP,对行进行kmp操作
int i, j;
for ( nxt[1] = 0, j = 0, i = 2; i <= r; i++ ) {
while ( j > 0 && strcmp(g[j + 1] + 1, g[i] + 1) )
j = nxt[j];
if ( !strcmp(g[j + 1] + 1, g[i] + 1) )
j++;
nxt[i] = j;
}
return r - nxt[r];//求得行字符串最小循环节长度
}
int
ckmp(void) {//column_KMP,列进行KMP操作
int i, j;
for ( nxt[1] = 0, j = 0, i = 2; i <= c; i++ ) {
while ( j > 0 && !eq( j + 1, i ) )
j = nxt[j];
if ( eq( j + 1, i ) )
j++;
nxt[i] = j;
}
return c - nxt[c];//求得列字符串最小循环节长度
}
int
main() {
int i, j;
scanf("%d%d", &r, &c);
for ( i = 1; i <= r; i++ )
scanf("%s", g[i] + 1);
printf("%d\n", rkmp() * ckmp());
return 0;
}
无注释代码:
#include <string.h>
#include <stdio.h>
#define MAXR 10000
#define MAXC 75
char g[MAXR][MAXC + 1];
short prv[MAXR];
int r, c;
int
c_eq( int x, int y ) {
int i;
for ( i = 0; i < r; i++ )
if ( g[i][x] != g[i][y] )
return 0;
return 1;
}
int
build_r(int r) {
int i, j;
prv[0] = -1;
for ( j = -1, i = 1; i < r; i++ ) {
while ( j > -1 && strcmp(g[j + 1], g[i]) ) j = prv[j];
if ( !strcmp(g[j + 1], g[i]) ) j++;
prv[i] = j;
}
return r - 1 - prv[r - 1];
}
int
build_c(int c) {
int i, j;
prv[0] = -1;
for ( j = -1, i = 1; i < c; i++ ) {
while ( j > -1 && !c_eq( j + 1, i ) ) j = prv[j];
if ( c_eq( j + 1, i ) ) j++;
prv[i] = j;
}
return c - 1 - prv[c - 1];
}
int
main() {
int i;
scanf("%d%d", &r, &c);
for ( i = 0; i < r; i++ ) scanf("%s", g[i]);
printf("%d\n", build_r(r) * build_c(c));
return 0;
}
单词解释:
milk:vt, 挤奶
grid:n, 网格,格子
column:n, 一列,列
feeding:n, 饲养
lable:vt, 标注,贴标签于
breed:n, (生物)品种,种类
repetitively:adv, 重复地
tile:vt, 铺瓦片
evenly:adj, 平均地,均匀地
intervening:adj, 介于中间的