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

来源:互联网 发布:卡密社区源码 编辑:程序博客网 时间:2024/06/08 07:06

题目链接: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 0x7f7f7f7fusing 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 0x7f7f7f7fusing 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;}

运行结果:
这里写图片描述

1 0