您的位置:首页 > 其它

hdu 5510 Bazinga (字符串匹配 kmp/strstr加个剪枝←据说这些都不是正解)

2016-10-02 11:48 501 查看
题目链接:hdu 5510

Bazinga

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

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

4

5

ab

abc

zabc

abcd

zabcd

4

you

lovinyou

aboutlovinyou

allaboutlovinyou

5

de

def

abcd

abcde

abcdef

3

a

ba

ccc

Sample Output

Case #1: 4

Case #2: -1

Case #3: 4

Case #4: 3

字符串匹配问题。

题目要求的是满足以下条件的一个字符串:

1.此字符串的上方的字符串里至少有一个不是它的子串;

2.满足条件一的字符串里边下标最大的。最后输出它的下标(+1);

时隔多年过来做kmp发现自己快不会用模板了……最终还是努力的改错改过了。

问题就在于耿直暴力绝壁超时,于是看了下题解,滚来博客整理优化暴力思路没错是暴力最后还是卡过……之后有时间再来整理别的正常点的算法。

顺序往下求出所有的满足条件的字符串,如果有某个字符串是它下面的某字符串的子串,就vis[k] = false;标记它,下次遍历时就不用再判断它是不是当前串的子串了。解释如下:

1.如果当前串前面的某个串s的是它的子串,那么串s的子串a, b, c等也一定是当前串的子串。因此不用遍历子串a, b, c也可以得到正解。

2.如果当前串前面的某个串s不是当前串的子串,那以它为子串的其它串a,b,c等也一定不是当前串的子串,因此标记串s,判断a,b,c也可以得出正解。

我已经不认识串这个字了……

具体看代码。



======================================

10.2晚上更新

之前自己看的c语言都忘光了……忘了string.h里面的strstr函数,看完别人的暴力题解才发现自己白白多花时间改了那么久的kmp出来速度还比strstr慢,淦。在这道题里用kmp简直就是大材小用浪费时间。

代码在第一版基础上进行了改变,贴在第一版代码后面。

#include <iostream>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <algorithm>
#include <stack>
#include <cmath>
#define LL long long
#define M 505
#define MM 2005
#define INF 0x7f7f7f7f

using namespace std;

char s[M][MM];
bool vis[M], flag[M];
int nxt[MM], n, leng[M];

void getnxt(int len, char txt[])//求nxt数组,耿直套模板即可。
{
nxt[0] = -1;
int i = 0, j = -1;

while(i < len)
{
while(j >= 0 && txt[i] != txt[j])
j = nxt[j];

j++, i++;
if(txt[i] == txt[j])
nxt[i] = nxt[j];
else
nxt[i] = j;
}
}

bool kmp(int len, int id)//与模板相比少许修改,遍历上方字符串
{
for(int k = 0; k < id; k++)
{
if(vis[k])//如果已经判断出第k串是某个串的子串,就跳过
{
getnxt(leng[k], s[k]);
int i = 0, j = 0;
while(i < len)
{
while(j >= 0 && s[id][i] != s[k][j])
j = nxt[j];

i++, j++;
if(j == leng[k])
{
vis[k] = false;
break;
}
}
if(j != leng[k])//如果当前串前面的某个串不是它的子串
return false;
}
}
return true;//如果当前串前面的所有串都是它的子串
}

int main()
{
int T, ans;
scanf("%d", &T);
for(int i = 1; i <= T; i++)
{
ans = -2;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%s", s[i]);
leng[i] = strlen(s[i]);
}

memset(vis, true, sizeof(vis));
memset(flag, true, sizeof(flag));
for(int i = 1; i < n; i++)
{
flag[i] = kmp(leng[i], i);
if(!flag[i])//寻找下标最大的那个串。
ans = i;
}
printf("Case #%d: %d\n", i, ans + 1);
}
return 0;
}


运行结果:



#include <iostream>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <algorithm>
#include <stack>
#include <cmath>
#define LL long long
#define M 505
#define MM 2005
#define INF 0x7f7f7f7f

using namespace std;

char s[M][MM];
bool vis[M];

int main()
{
int T, n, ans;
scanf("%d", &T);
for(int i = 1; i <= T; i++)
{
ans = -2;
memset(vis, true, sizeof(vis));
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%s", s[i]);
for(int j = 0; j < i; j++)
{
if(vis[j])
{
if(!strstr(s[i], s[j]))
ans = i;
else
vis[j] = false;
}
}
}
printf("Case #%d: %d\n", i, ans + 1);
}
return 0;
}


运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  kmp