POJ 2744 子串 解题报告

现在有一些由英文字符组成的大小写敏感的字符串,你的任务是找到一个最长的字符串x,使得对于已经给出的字符串中的任意一个y,x或者是y的子串,或者x中的字符反序之后得到的新字符串是y的子串。

输入:

输入的第一行是一个整数t(1≤t≤10),t表示测试数据的数目。对于每一组测试数据,第一行是一个整数n(1≤n≤100),表示已经给出n个字符串。接下来n行,每行给出一个长度在1和100之间的字符串。

输出:

对于每一组测试数据,输出一行,给出题目中要求的字符串x的长度。

样例输入:

2
3
ABCD
BCDFF
BRCD
2
rose
orchid

样例输出:

2
2

执行结果:


思路:

我的想法有些麻烦,thanks to这题数据范围不大...不然肯定t掉,身为一个acm小白很抱歉写了复杂度如此之高的代码 T_T

下面来讲下我是如何水过的这个题吧~

首先这题题意坑点很大,就是你找的这个子串,它的顺序或反序是所有串的子串即可,注意并不是单一的,我的意思是,不是说你找的子串要么顺序被其他串包含,要么反序被包含。而是如果顺序没包含进去的,但是反序包含进去了,也可以~

所以我首先找最短的串,因为,答案所求串长一定小于等于最短串的长度,所以暴力枚举最短串的子串以及反序子串是第一步,三层循环,超级暴力,因为只有1e2的长度,我才敢这么写。代码如下:

int p = 0; //记录子串个数
        for(i = 0; i < minl; i++) {
            for(j = i; j < minl; j++) {
                for(int k = i; k <= j; k++) s0[k - i] = s[pos][k]; //暴力枚举子串
                s0[j - i + 1] = '\0';
                p++;
                int l0 = strlen(s0);
                for(int k = 0; k < l0; ++k) st[p][k] = s0[k]; //最短串所有子串
                for(int k = 0, a = l0 - 1; k < l0, a >= 0; ++k, --a) str[p][a] = s0[k]; //最短串所有子串反序
            }
        }

        //for(int i = 1; i <= p; i++) printf("%s %s\n", st[i], str[i]);

上面加注释的那行代码就测了下输出,发现没毛病~ Ok ~ Go on ~

然后是核心思想:

用枚举出的正反子串与输入进去的这些串进行strstr()函数判断包含与否。如果包含,用一个max维护即可,这里要注意,平时喜欢 const int Inf = 1e9;  然后就int maxn = -Inf;这种写法在这题显然搓掉,因为若所有串没有公共子串,应该输出0,而你最后维护出的max就是答案,在无公共子串的情况下,你会输出-Inf这个值,所以max初值应赋值为0.

详细代码如下:(代码对各·数组变量功能注释特别详细,一看就能get到要点~)

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int Inf = 1e6;
const int Maxx = 1e2 + 7;
const int MaxN = 1e6;
char s0[Maxx]; //最短串的枚举子串
char st[MaxN][Maxx]; //最短串所有子串的集合
char str[MaxN][Maxx]; //最短串所有子串的反序
int cas;
int n;

int main() {
    char s[Maxx][Maxx];
    scanf("%d", &cas);
    while(cas--) {
        int minl = Inf;
        int maxl = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%s", s[i]);
        for(int i = 1; i <= n; i++) {
            if(strlen(s[i]) < minl) minl = strlen(s[i]);
        }
        int pos; //最短串位置
        for(int i = 1; i <= n; i++) {
            if(strlen(s[i]) == minl) {
                pos = i;
                break;
            }
        }
        int i, j;
        int p = 0; //记录子串个数
        for(i = 0; i < minl; i++) {
            for(j = i; j < minl; j++) {
                for(int k = i; k <= j; k++) s0[k - i] = s[pos][k]; //暴力枚举子串
                s0[j - i + 1] = '\0';
                p++;
                int l0 = strlen(s0);
                for(int k = 0; k < l0; ++k) st[p][k] = s0[k]; //最短串所有子串
                for(int k = 0, a = l0 - 1; k < l0, a >= 0; ++k, --a) str[p][a] = s0[k]; //最短串所有子串反序
            }
        }
        //for(int i = 1; i <= p; i++) printf("%s %s\n", st[i], str[i]);
        for(int i = 1; i <= p; i++) {
            bool flg = 1;
            for(int j = 1; j <= n; j++) {
                if(strstr(s[j], st[i]) == 0 && strstr(s[j], str[i]) == 0) {
                    flg = 0;
                    break;
                }
            }
            if(flg) {
                int len = strlen(st[i]);
                maxl = max(maxl, len);
            }
        }
        printf("%d\n", maxl);
    }
    return 0;
}

你可能感兴趣的:(水题合集)