HDU - 5510 Bazinga(暴力剪枝 + KMP || strstr)

55 篇文章 0 订阅
1 篇文章 0 订阅

点击打开题目链接

Bazinga

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

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

Source

2015ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)

Recommend

wange2014

Statistic | Submit | Discuss | Note

题目大意:

给出n个字符串,找到最大的j使得从1->j-1中存在s[i]不是s[j]的子串。

思路:

如果直接枚举两个串复杂度为50*500*500=12500000,还不加匹配算法的复杂度,超时。

现在想可不可以剪枝。

两层循环,第一层i枚举所有子串,第二层j枚举母串。

如果s[i]是s[j]的子串,则s[i]串的贡献完全可以转化成s[j]串,则直接break到下一个子串.

如果s[i]串不是s[j]的子串,则s[j]串即为满足题目要求的,标记下来,以后遍历母串跳过s[j]即可。

然后遍历寻找最大的j即可。

KMP版代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int maxn = 500 + 5;
char s[maxn][2500];
int t, n;
int p[maxn], nxt[maxn][2500], len[maxn];

void getNext(int t) {
    int i, j;
    j = nxt[t][0] = -1;
    i = 0;
    while(i < n) {
        while(j != -1 && s[t][i] != s[t][j]) j = nxt[t][j];
        nxt[t][++i] = ++j;
    }
}

//判断s[v]是否包含s[u]
int kmp(int v, int u) {
    int i, j;
    i = j = 0;
    while(i < len[v]) {
        while(j != -1 && s[v][i] != s[u][j]) j = nxt[u][j];
        i++;j++;
        if(j >= len[u]) {
            return 1;
        }
    }
    return 0;
}

int solve() {
    memset(p,1,sizeof(p));
    int ans = -1;
    for(int i = 1; i < n; i++) {
        for(int j = i + 1; j <= n; j++) {
            if(p[j]) {
                if(kmp(j, i)) break;
                else {
                    p[j] = 0;
                    ans = max(ans, j);
                }
            }
        }
    }
    return ans;
}

int main() {
    scanf("%d", &t);
    for(int kase = 0; kase < t; kase++) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%s", s[i]);
            len[i] = strlen(s[i]);
            getNext(i);
        }
        printf("Case #%d: %d\n",kase+1, solve());
    }
    return 0;
}


看了别人的AC,才直到有strstr函数,可以寻找s[i]在s[j]串中的位置。

strstr版代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

using namespace std;
const int maxn = 500 + 5;
char s[maxn][2500];
int t, n;
int p[maxn];

int solve() {
    memset(p,1,sizeof(p));
    int ans = -1;
    for(int i = 1; i < n; i++) {
        for(int j = i + 1; j <= n; j++) {
            if(p[j]) {
                if(strstr(s[j], s[i])) break;
                else {
                    p[j] = 0;
                    ans = max(ans, j);
                }
            }
        }
    }
    return ans;
}

int main() {
    scanf("%d", &t);
    int kase = 0;
    while(t--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) 
            scanf("%s", s[i]);
        printf("Case #%d: %d\n",++kase, solve());
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chook_lxk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值