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≤i≤n) 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\n",++cnt,ans);
}
return 0;
}