poj(2185) Milking Grid (很好的kmp题目)

http://poj.org/problem?id=2185

题意:给你一个字符矩阵,求出它的最小覆盖子矩阵,即使得这个子矩阵的无限复制扩张之后的矩阵,能包含原来的矩阵。 即二维的最小覆盖子串。

思路:KMP很好的一道题。首先易证:最小覆盖子矩阵一定靠左上角。那么,我们考虑求出每一行的最小重复串长度,所有行的最小重复串的长度的lcm就是最小重复子矩阵的宽。然后我们对列也做相同的操作。于是我们就可以求得最小重复子矩阵的大小了。(这里要注意一点:当所得的宽大于原来的宽时,就让等于原来的宽,长也如此)。算法实现:算法的核心在于高效的求出每一行和每一列的最小重复串,这个可以最原串做一次KMP中的get_next()。

如果对于最小区间覆盖不了解的话,请移步:http://blog.csdn.net/fjsd155/article/details/6866991

(注:以上部分为转载)

 

#include <stdio.h>
#include <iostream>
#include <string>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <vector>
#include <map>
using namespace std;
const int maxn = 10001;
char grid[maxn][76];
int next[maxn];
int r,c;
int res1,res2;
int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
int lcm(int a,int b){
    return a/gcd(a,b)*b;
}
void getnext_r(int x){
    int i = 0,j = -1;
    next[0] = -1;
    while(i < c){
        if(j == -1 || grid[x][i] == grid[x][j])
            next[++i] = ++j;
        else
            j = next[j];
    }
    res1 = lcm(res1,c - next[c]);
}
void getnext_c(int x){
    int i = 0,j = -1;
    next[0] = -1;
    while(i < r){
        if(j == -1 || grid[i][x] == grid[j][x])
            next[++i] = ++j;
        else
            j = next[j];
    }
    res2 = lcm(res2,r - next[r]);
}
int main(){
    while(~scanf("%d%d",&r,&c)){
        for(int i = 0;i < r;i++)
            scanf("%s",grid[i]);
        res1 = 1;
        for(int i = 0;i < r;i++){
            getnext_r(i);
            if(res1>=c){
                res1 = c;
                break;
            }
        }
        res2 = 1;
        for(int i = 0;i < c;i++){
            getnext_c(i);
            if(res2>=r){
                res2 = r;
                break;
            }
        }
        printf("%d\n",res1*res2);
    }
    return 0;
}

 

 

原文地址:https://www.cnblogs.com/Roly/p/3053240.html