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

奶牛阵列

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 5
ABABA
BABAB

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 10005
using 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值