POJ 1226 Substrings 暴力枚举+KMP算法

/*题意就是给你若干字符串,找出这些字符串中最大的相同字母个数,正逆序都可以。

想法是,因为必须是每个字符串中共有的部分,所以可以随便拿一个字符串来枚举他的子串。

我拿了a[1].然后枚举他不同长度的子串。

从大到小,如果KMP(子串,原串(2-n))||(KMP(逆序子串,原串(2-n)))成立的话,则该子串就是最大相同子串,因为是从大到小枚举的直接输出该串长度,结束。*/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <iomanip>
#define PI acos(-1.0)
#define Max 2005
#define inf 1<<28
using namespace std;
char a[Max][Max];
int next[Max],n;

void findnext(char a[])
{
    int k=-1;
    int j=0;
    next[0]=-1;
    int l=strlen(a);
    while(j<l)
    {
        if(k==-1||a[k]==a[j])
        {
            k++,j++;
            next[j]=k;
        }
        else k=next[k];//当前缀字符与后缀字符不相等时返回前一状态
    }
}


int KMP(char a[],char b[])
{
    findnext(a);
    int posa=0,posb=0;
    int la=strlen(a),lb=strlen(b);
    while(posa<la&&posb<lb)
    {
        if(posa==-1||a[posa]==b[posb])
        {
            posa++,posb++;//当匹配成功时,两个字符串各后移一个字符
        }
        else posa=next[posa];
    }
    if(posa<la)return 0;//匹配失败
    //当匹配成功的时候posa的指针应该指向a字符串的最后一个字符+1处,也就是la处
    else return 1;//匹配成功,若返回首地址可以写return posb-posa;
}


int main()
{
    int i,j,k,l,m,T;
    char reva[Max],revb[Max];
    cin>>T;
    while(T--)
    {
        int min_i=-1;
        int min_l=1000;
        cin>>n;
        for(i=1; i<=n; i++)
        {
            scanf("%s",a[i]);//网上看到一种写法就是直接在这一步中找出长度最小的原串,然后枚举该串。多一个比较的步骤,但是时间应该比我这个快
				
        }
        l=strlen(a[1]);
        bool flag=0;//标记未找到最大子串
        for(i=l;i>0;i--)//从最大子串开始枚举
        {
            for(j=0;j<l-i+1;j++)//枚举的次数
            {
                int count=0;
                for(k=j;k<=j+i-1;k++)//本次枚举的正序串
                reva[count++]=a[1][k];
                reva[count]='\0';
                count=0;
                for(k=j+i-1;k>=j;k--)//本次枚举的逆序串
                revb[count++]=a[1][k];
                revb[count]='\0';
                count=0;
                for(k=2;k<=n;k++)//是否与每一个原串都匹配
                {
                    if(KMP(reva,a[k])||KMP(revb,a[k]))
                    count++;
                }
                if(count==n-1)//count=n-1则全部匹配,输出子串的长度即为答案
                {
                    flag=1;
                    cout<<strlen(reva)<<endl;
                    break;
                }
            }
            if(flag)
            break;
        }
        if(!flag)
        cout<<0<<endl;

    }
    return 0;
}


考察KMP的应用以及子串的构造。枚举居然没超时。。


你可能感兴趣的:(算法)