题目链接:http://poj.org/problem?id=2185
题意:给出一个R*C(10000 * 75)的矩形字符串,然你求最小的不严格重复矩阵,比如,ABA,最小的重复矩阵是AB,经过复制ABAB,可以把ABA完全覆盖掉。
题解:
题意很好理解,首先我们应该清楚,最小重复字串一定实在左上角。我们可以找到宽的最小共同重复串,然后,我们就可以对高进行kmp。答案即为w*h的值。对于宽,我们可以暴力找,枚举每一行的所有起点为0的字串,判断该长度是否满足重复,然后,我们所有行的最小共同的重复字串,即为宽w,对于高,只需要进行一次kmp求最小重复字串即可。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1e4 + 15; char s[maxn][80], T[80]; int net[maxn]; int bit[80]; int R, C; int main() { int ans = 0; scanf("%d%d", &R, &C); for(int i = 0; i < C; i++) bit[i] = 0; for(int i = 0; i < R; i++) { scanf("%s", s[i]); strcpy(T, s[i]); for(int j = C - 1; j >= 1; j--) { T[j] = 0; int x = 0, y = 0; for(; s[i][y]; x++, y++) { if(!T[x]) x = 0; if(T[x] != s[i][y]) break; } if(!s[i][y]) bit[j]++; } } for(int i = 1; i < C; i++) if(bit[i] == R) { ans = i; break; } if(!ans) ans = C; for(int i = 0; i < R; i++) s[i][ans] = 0; net[0] = -1; int j = 0, k = -1; while(j < R) { if(k == -1 || !strcmp(s[k], s[j])) net[++j] = ++k; else k = net[k]; } printf("%d\n", (R - net[R])*ans); //行列相乘即为最终结果 return 0; }
有一个优化:http://poj.org/showmessage?message_id=168710
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1e4 + 15; char s[maxn][80], T[80]; int net[maxn]; int bit[80]; int R, C; int main() { int ans = 0; scanf("%d%d", &R, &C); for(int i = 0; i < C; i++) bit[i] = 0; for(int i = 0; i < R; i++) { scanf("%s", s[i]); strcpy(T, s[i]); for(int j = C - 1; j >= 1; j--) { T[j] = 0; int x = 0, y = 0; for(; s[i][y]; x++, y++) { if(!T[x]) x = 0; if(T[x] != s[i][y]) break; } if(!s[i][y]) bit[j]++; } } for(int i = 1; i < C; i++) if(bit[i] == R) { ans = i; break; } if(!ans) ans = C; net[0] = -1; int j = 0, k = -1; while(j < R) { if(k == -1 || !strcmp(s[k], s[j])) net[++j] = ++k; else k = net[k]; } printf("%d\n", (R - net[R])*ans); //行列相乘即为最终结果 return 0; }