HDU 5510(KMP+思维)

传送门

题面:

Bazinga

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 6560    Accepted Submission(s): 2003

 

Problem Description

Ladies and gentlemen, please sit up straight.
Don't tilt your head. I'm serious.


For n given strings S1,S2,⋯,Sn, labelled from 1 to n, you should find the largest i (1≤in) such that there exists an integer j (1≤j<i) and Sj is not a substring of Si.

A substring of a string Si is another string that occurs in Si. For example, ``ruiz" is a substring of ``ruizhang", and ``rzhang" is not a substring of ``ruizhang".

Input

The first line contains an integer t (1≤t≤50) which is the number of test cases.
For each test case, the first line is the positive integer n (1≤n≤500) and in the following n lines list are the strings S1,S2,⋯,Sn.
All strings are given in lower-case letters and strings are no longer than 2000 letters.

Output

For each test case, output the largest label you get. If it does not exist, output −1.

Sample Input


 

45ababczabcabcdzabcd4youlovinyouaboutlovinyouallaboutlovinyou5dedefabcdabcdeabcdef3abaccc

Sample Output


 

Case #1: 4Case #2: -1Case #3: 4Case #4: 3

    

    题目描述:每次给你n个字符串S,问你最大的i,使得字符串Sj(0<=j<i)全都不是Si的字串。

    题面分析:通过读题,因为要求某个串是否是某个串的字串,因此可以判断出这是一道很经典的字符串匹配问题。

    从题目来看,这貌似就是一道很普通的多模匹配的问题,用AC自动机去解决,但是这题如果用AC自动机去做,先建树再用每一个字符串进行匹配的话会导致TLE。因此AC自动机在这个题目上并不适合。

    因此我们得拓宽我们的思维。

    进一步分析我们可以发现,对于第j串字符串,倘若前j串都是j的字串,那么我们下一步只需要判断j是否是j+1的字串即可(因为如果j是j+1的字串,而前j串又是j的字串,易得j+1串也是前j串的字串,进而得出前j+1串是j+1串的字串。)

    而倘若j串并不是j+1串的字串,那么下一步只需判断j串是否是j+2串的字串即可。

    因此,这道题就被巧妙地转化成了单模匹配的问题了。如此我们就可以通过KMP算法,使用类似指针的做法去用较短的时间匹配出答案。

    附上KMP算法的代码:

#include <bits/stdc++.h>
#define maxn 1005
using namespace std;
namespace CHENJR{//此处运用了命名保护,防止next数组报错

int next[maxn];
string str[maxn];
void get_next(string s){
    memset(next,0,sizeof(next));
    int len=s.length();
    int i,j;
    j=next[0]=-1;
    i=0;
    while(i<len){
        while(j!=-1&&s[i]!=s[j]) j=next[j];
        next[++i]=++j;
    }
}
bool kmp(string a,string b){
    int lena=a.length();
    int lenb=b.length();
    get_next(b);
    int i=0,j=0;
    while(i<lena){
        while(j!=-1&&a[i]!=b[j]) j=next[j];
        i++,j++;
        if(j>=lenb) return true;
    }
    return false;
}

void main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    int cnt=0;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>str[i];
        }
        int j=1;
        
        int ans=-1;
        for(int i=2;i<=n;i++){
            while(j<i&&kmp(str[i],str[j])){
                j++;
            }
            if(j<i) ans=i;
        }
        cout<<"Case #"<<++cnt<<": "<<ans<<endl;
    }
}

}
int main()
{
    CHENJR::main();
    exit(0);
}

    然而事实上,在头文件string.h内是含有一个strstr()函数用来寻找字串的。(但是需要注意的是,strstr()这个函数在最坏的情况下O(n^2)的复杂度,而kmp算法的复杂度是稳定在O(n)的。因此使用strstr()函数有风险,但是很省力省时间)对于这题,用strstr()函数是没有任何问题的。对于这个函数就当小小的积累了吧。

    附上代码:

#include <bits/stdc++.h>
#define maxn 2005
using namespace std;
char str[maxn][maxn];
int main()
{
    int t;
    int cnt=0;
    scanf("%d",&t);
    while(t--){
        memset(str,0,sizeof(str));
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",str[i]);
        }
        int ans=-1,j=1;
        for(int i=2;i<=n;i++){
            while(j<i&&strstr(str[i],str[j])){
                j++;
            }
            if(j<i) ans=i;
        }
        printf("Case #%d: %d
",++cnt,ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Chen-Jr/p/11007300.html