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