KMP_next数组应用_循环元_POJ2185_Milking Grid

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/83860313

点此打开题目页面

思路分析:

    设给定图形可由A\timesB子矩形重复而成, 稍一想便知, 给定图形必定可由其最左上角的A\timesB子矩形重复而成. 因此只需找到所有行(长度C)同时满足S[1...k] = S[C - k + 1...C]的最大的k和所有列(长度为R)同时满足T[1...m] = T[R - m + 1...R]的最大的m, (C - k)\times (R - m)即为最小循环单元的面积, 具体实现如下AC代码所示:

//POJ2185_Milking Grid
#include <iostream>
#include <cstdio>
#include <set>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXR = 1e4 + 5, MAXC = 80;
char g[MAXR][MAXC]; int R, C;
int rnext[MAXR][MAXC], cnext[MAXC][MAXR];//rnext:行next, cnext: 列next 
int cntNext[MAXR];//cntNext[i]:next[i]的个数 
int main(){
	scanf("%d %d", &R, &C);
	for(int i = 1; i <= R; ++i) scanf("%s", g[i] + 1);
	//计算行next
	for(int i = 1; i <= R; ++i){
		rnext[i][1] = 0;
		for(int j = 2; j <= C; ++j){
			int t = rnext[i][j - 1];
			while(t && g[i][t + 1] != g[i][j]) t = rnext[i][t];
			if(t > 0) rnext[i][j] = t + 1;
			else rnext[i][j] = g[i][1] == g[i][j]? 1: 0;
		}
	} 
	//计算列next
	for(int i = 1; i <= C; ++i){
		cnext[i][1] = 0;
		for(int j = 2; j <= R; ++j){
			int t = cnext[i][j - 1];
			while(t && g[t + 1][i] != g[j][i]) t = cnext[i][t];
			if(t > 0) cnext[i][j] = t + 1;
			else cnext[i][j] = g[1][i] == g[j][i]? 1: 0;			
		}
	} 
	//计算行next交集
	for(int i = 1; i <= R; ++i) 
		for(int t = rnext[i][C]; t; ++cntNext[t], t = rnext[i][t]);	
	int rlen = C; 
	for(int i = C; i >= 1; --i) 
		if(cntNext[i] == R){
			rlen = C - i; break;
		}
	memset(cntNext, 0, sizeof(cntNext));
	for(int i = 1; i <= C; ++i)
		for(int t = cnext[i][R]; t; ++cntNext[t], t = cnext[i][t]);
	int clen = R;
	for(int i = R; i >= 1; --i)
		if(cntNext[i] == C){
			clen = R - i; break;
		}
	cout << clen * rlen << endl;
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/solider98/article/details/83860313
今日推荐