poj 2185 Milking Grid (字符串__KMP好题)

题目链接:http://poj.org/problem?id=2185


题目大意:给定一个n*m的字符矩阵,每行字符会有若干个相同的串组成,最后一个重复串不一定要完整。问这个矩阵可由面积最小为多少的矩阵组成。


解题思路:第一次看完题目,有点不解,又看了下测试数据,觉得没有思路,又重复看了一次题目,注意到一句话:Note that the dimensions of the small rectangular unit do not necessarily need to divide evenly the dimensions of the entire milking grid。在看一遍测试数据就大概理解清楚题意了,就是每行的重复子串长度的最小公倍数,如果超过n,则为n.提交果断地Wa了,后来发现第二行的首字母和第一行的不一样,这样两行不能简单地这样求公倍数得到ans1,所以加了各判断:如果两行不想等,直接输出n*m.提交又Wa。Wa了两次以后发现其实可以几行几行的循环,也是重复子串。所以,针对每列求最短重复子串长度,然后求最小公倍数,求出来的ans2表示矩阵中有ans2行是和后面的重复的,也要判断是否大于m,大的话ans2为m.最后输出ans1*ans2.本题有一定思维难度。


测试数据:

3 5
ABCDE
BCDEF
CDEFG
3 5
ABABA
ABABA
ABABA
4 5 
ABABA
BABAB
ABABA
BABAB
4 5
ABABA
BABAA
ABCCA
BAABA


代码:

#include <stdio.h>
#include <string.h>
#define MAX 10010
#define MIN 110


int len,next[MAX];
int row[MAX],col[MIN];
char str[MAX][MIN],rostr[MIN][MAX];


int Kmp(char *str) {

	int i,j,k,len;
	len = strlen(str);


	i = 0,j = -1;
	next[i] = -1;
	while (i < len) {

		if (j == -1 || str[i] == str[j])
			i++,j++,next[i] = j;
		else j = next[j];
	}


	return len - next[len];
}
int gcd(int n,int m) {

	int r = n % m;
	while (r != 0) {

		n = m,m = r;
		r = n % m;
	}


	return m; 
}
int lcd(int n,int m) {

	return n / gcd(n,m) * m;
}


int main()
{
	int i,j,k,m,n;
	int res,ans,flag;


	while (scanf("%d%d",&n,&m) != EOF) {

		flag = 0,res = ans = 1;
		for (i = 0; i < n; ++i) {

			scanf("%s",str[i]);
			row[i] = Kmp(str[i]);
		}
		for (i = 0; i < n; ++i)
			for (j = 0; j < m; ++j)
				rostr[j][i] = str[i][j];
		for (j = 0; j < m; ++j)
			col[j] = Kmp(rostr[j]);

	
		for (i = 0; i < m; ++i)
			ans = lcd(ans,col[i]);
		ans = n < ans ? n : ans;
		for (i = 0; i < ans; ++i)
			res = lcd(res,row[i]);
		res = m < res ? m : res;
		printf("%d\n",ans * res);
	}
}


本文章为ZeroClock原创,但可以转载,因为我们是兄弟!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值