POJ 2185 Milking Grid(二维KMP)

超级传送门:http://poj.org/problem?id=2185


这道题网上很多其他的blog上的题解都是错的,由于题目自身数据比较水,便都混过去了。其中一种典型的错误解法是求出每一行/列的最小覆盖长度(ABCAB的最小覆盖长度就是3,即对应ABC),然后LCM,若结果大于串长,则取串长。这是一种典型的错误贪心,诸如:

2 8
ABCDEFAB
AAAABAAA

这组数据,正解应该是12,即2*6,但求LCM的话就是LCM(5, 6) = 30,然后再比较串长,得到结果8,2*8=16 。

正确的思路应该是这样的:

1.先纵向匹配,把每一行看成一个字符,求得可覆盖循环节长度plen。

2.将0~plen-1行矩阵转置,变成c行plen列。

3.将此新矩阵每行看成一个字符进行匹配,得到可覆盖循环节长度revplen。

4.结果应为plen * revplen 。


代码:

#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 10100;
const int maxm = 10100;

int P[maxm];
char B[maxm][80];
char revB[80][maxm];

int n, m;

void preprocess(char (*B)[80], int* P, int m = -1)
{
    P[0] = -1;
    int j = -1;

    for (int i = 1; i < m; i++)
    {
        while (j != -1 && strcmp(B[j + 1], B[i]))
            j = P[j];

        if (!strcmp(B[j + 1], B[i]))
            j++;
        P[i] = j;
    }
}

void revpreprocess(char (*B)[maxm], int* P, int m = -1)
{
    P[0] = -1;
    int j = -1;

    for (int i = 1; i < m; i++)
    {
        while (j != -1 && strcmp(B[j + 1], B[i]))
            j = P[j];

        if (!strcmp(B[j + 1], B[i]))
            j++;
        P[i] = j;
    }
}

void reverse(char (*revB)[maxm], char (*B)[80], int r, int c)
{
    for (int i = 0; i < c; i++)
    {
        for (int j = 0; j < r; j++)
            revB[i][j] = B[j][i];
        revB[i][r] = '\0';
    }
}

int main()
{
    int r, c;
    while (scanf("%d%d", &r, &c) > 0)
    {
        for (int i = 0; i < r; i++)
            scanf("%s", B[i]);

        preprocess(B, P, r);

        int plen = r - P[r - 1] - 1;

        reverse(revB, B, plen, c);
        revpreprocess(revB, P, c);

        int revplen = c - P[c - 1] - 1;

        printf("%d\n", plen * revplen);
    }

    return 0;
}

再附上一些典型测试数据:

4 6
ABAABA
ABAABA
ABAABA
ABAABA

2 5
ABABA
ABABA

1 1
A

1 2
AA

1 2
AB
1 5
ABCAB

4 6
ABAABA
ABAABA
ABAABC
ABAABA

2 8
ABCDEFAB
ABCDEABC
2 8
ABCDEFAB
AAAABAAA

4 3
abc
bcd
def
abc

2 2
aa
aa

4 4
ABAB
CDCD
BABA
DCDC

2 8
ACBABACB
ACBABACB

4 1
A
A
B
A

4 4
abca
abva
abxa
abca

3 5
ABCDE
BCDEF
CDEFG

4 5 
ABABA
BABAB
ABABA
BABAB

4 5
ABABA
BABAA
ABCCA
BAABA

输出:

3
2
1
1
2
3
18
16
12
9
1
8
5
3
9
15
4
20


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值