POJ 2185 Milking Grid(KMP最小循环节)

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 }
原文地址:https://www.cnblogs.com/zyb993963526/p/6753174.html