http://poj.org/problem?id=2185
题意:
给出一个r行c列的字符矩阵,求最小的覆盖矩阵可以将原矩阵覆盖,覆盖矩阵不必全用完。
思路:
我对于字符串的最小循环节是这么理解的:
如果next[12]=5,那么前5个前缀字符和后5个后缀字符是一样,但是此时还需要加上中间的2个,所以循环节为7。
如果next[12]=7,那么中间2个既出现在了前缀里,也出现在了后缀里,所以中间的2个字符等于开头的两个字符。此时循环节为5。
这样的话,字符串的最小循环节就是 len - next[len] 。
那么这道题的话:
对每一行求最小循环节,并对所有行求最小公倍数。
对每一列求最小循环节,并对所有列求最小公倍数。
相乘得最小面积。
注意:
如果此时的最小公倍数大于了行或列,可以直接等于行或列并退出了。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 using namespace std; 10 11 const int maxn=100+5; 12 13 int r,c; 14 char str[10005][80]; 15 int next[10005]; 16 17 int gcd(int a,int b) 18 { 19 return b==0?a:gcd(b,a%b); 20 } 21 22 void get_nextrow(int r) 23 { 24 int i=-1,j=0; 25 next[0]=-1; 26 while(j<c) 27 { 28 if(i==-1 || str[r][i]==str[r][j]) 29 next[++j]=++i; 30 else 31 i=next[i]; 32 } 33 } 34 35 void get_nextcol(int c) 36 { 37 int i=-1,j=0; 38 next[0]=-1; 39 while(j<r) 40 { 41 if(i==-1 || str[i][c]==str[j][c]) 42 next[++j]=++i; 43 else 44 i=next[i]; 45 } 46 } 47 48 int main() 49 { 50 //freopen("D:\input.txt","r",stdin); 51 scanf("%d%d",&r,&c); 52 for(int i=0;i<r;i++) 53 scanf("%s",&str[i]); 54 55 int row=1; 56 for(int i=0;i<r;i++) 57 { 58 get_nextrow(i); 59 row=row*(c-next[c])/gcd(row,c-next[c]); 60 if(row>=c) 61 { 62 row=c; 63 break; 64 } 65 } 66 67 int col=1; 68 for(int i=0;i<c;i++) 69 { 70 get_nextcol(i); 71 col=col*(r-next[r])/gcd(col,r-next[r]); 72 { 73 if(col>=r) 74 { 75 col=r; 76 break; 77 } 78 } 79 } 80 printf("%d ",row*col); 81 }