1. 程式人生 > >KMP_next陣列應用_迴圈元_POJ2185_Milking Grid

KMP_next陣列應用_迴圈元_POJ2185_Milking Grid

點此開啟題目頁面

思路分析:

    設給定圖形可由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;
}