最大公共子串
Time Limit: |
1000MS |
Memory Limit: |
10000K |
Description
从一个给定的串中删去(不一定连续地删去)0个或0个以上的字符,剩下的字符按原来顺序组成的串是该串的子串。例如:“”,“a”,“xb”,“aaa”,“bbb”,“xabb”,“xaaabbb”都是串“xaaabbb”的子串。(例子中的串不包含引号。)
编程求N个非空串的最长公共子串的长度。限制:2≤N≤100;N个串中的字符只会是数字0,1,……,9或小写英文字母a,b,……,z;每个串非空且最多含100个字符:N个串的长度的乘积不会超过30000。
Input
文件第1行是一个整数T,表示测试数据的个数(1≤T≤10)。接下来有T组测试数据。各组测试数据的第1行是一个整数Ni,表示第i组数据中串的个数。各组测试数据的第2至N+1行中,每行一个串,串中不会有空格,但行首和行末可能有空格,这些空格当然不算作串的一部分。
Output
输出T行,每行一个数,第i行的数表示第i组测试数据中Ni个非空串的最长公共子串的长度。
Sample Input
1
3
ab
bc
cd
Sample Output
0
Hint
No hint.
Source
思路:
其实这道题应为“最大公共子序列”,一般定义子串是连续的,子序列则允许不连续,于是子序列的算法比子串麻烦得多。
》由于数据量不是很大,我还是采取了穷举的思路,至多100个字符串,令他们两两比对(至多5050对),记下两两的最大公共子串长度,而这些长度中最小的那个就是答案。
》关于公共子串的算法,用到DP,注意数组最好先加上两条都是0的边,实现起来更方便。
假设s1和s2比对,长度分别为l1,l2,先初始化数组,两条边a[0][x]和a[x][0](x = 0, 1, 2,……)全为0,其他位置全为-1;
对1~l1*1~l2的范围DP,a[i][j]表示s1从1到i的前缀与s2从1到j的前缀的最长公共子序列的长度;
递归:a[i][j] = max{ a[i - 1][j - 1] + same(s1[i], s2[j]),a[i - 1][j],a[i][j - 1] };