KMP(SOJ3596)

(2012-07-15 19:28:27)

SOJ3596: http://cstest.scu.edu.cn/soj/problem.action?id=3596

这道题采用的算法是DP+KMP,也是我做KMP的题中最具挑战性的一道。

首先利用KMP算法将所有的word在text中的所有位置(包括起点和终点)存到一个struct数组中。

至于DP,设xiaoye[i]表示以text[i]为结尾的结果,则求xiaoye[i]即是对所有的满足:j<i,xiaoye[j]>0,并且从字符text[j+1]到字符text[i]是某一个word条件的xiaoye[j]作xiaoye[i]=xiaoye[i]+xiaoye[j]的处理。但是直接按照这个思路处理会超时,倒过来进行就会大大提高效率。

这需要对struct数组进行预处理,也就是下面的cmp函数。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int next[1005];
char text[1000005];
int sum;
struct node
{
    char pattern[1005];
}word[1005];
struct Node
{
    int a;
    int b;
}position[1000005];
void get_next(char *pattern)
{
    int j=0;
    int k=-1;
    next[0]=-1;
    while(pattern[j])
    {
        if(k==-1 || pattern[j]==pattern[k])
        {
            ++j;
            ++k;
            if(pattern[j]!=pattern[k])
                next[j]=k;
            else
                next[j]=next[k];
        }
        else
            k=next[k];
    }
}
void KMP(char *pattern)
{
    int i=0;
    int j=0;
    int result=0;
    int lP=strlen(pattern);
    while(text[i])
    {
        if(text[i]==pattern[j])
        {
            i++;
            j++;
        }
        else if(next[j]==-1)
        {
            j=0;
            i++;
        }
        else
            j=next[j];
        if(j==lP-1)
        {
            position[sum].a=i-lP+1;
            position[sum++].b=i-1;
            j=next[j];//这里的next[j]即是next['0']的值,显然只能>=0.
            
        }
    }
}
int cmp(Node x,Node y)
{
    return x.a<y.a || (x.a==y.a && x.b<y.b);
}
int xiaoye[1000005];
int main()
{
    int test;
    int n;
    int i;
    scanf("%d",&test);
    while(test--)
    {    
        sum=0;
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%s",word[i].pattern);
            strcat(word[i].pattern,"0");
        }
        scanf("%s",text);
        for(i=0;i<n;i++)
        {
            get_next(word[i].pattern);
            KMP(word[i].pattern);
        }
        int lT=strlen(text);
        memset(xiaoye,0,sizeof(xiaoye));
        sort(position,position+sum,cmp);
        for(i=0;i<sum;i++)
        {
            if(position[i].a==0)
                xiaoye[position[i].b]++;
            else
            {
                xiaoye[position[i].b]=(xiaoye[position[i].b]+xiaoye[position[i].a-1])%835672545;
            }
        }
        printf("%d\n",xiaoye[lT-1]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值