题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1238
题意很简单,即找出最长的公共子串。
n个序列为p[0]...p[n-1],最长公共子串(顺着看,存放在p[0])的长度为maxlen,逆着看(存放在reverse数组里)的长度为maxlen1。由于公共子序列是每个序列的子串,因此不妨枚举第一个序列(其实枚举最短的那个子串是最好的)的每一个可能的子串s,以s为模式,分别以p[1]...p[n-1]为目标进行匹配计算。若s为p[1]...p[n-1]的公共子串(strstr[p[k], s) != 0,1 <= k <= n-1),且串的长度>maxlen(或者maxlen1),则将s调整为最长公共子串(maxlen(maxlen1) = s串的长度)。最后比较maxlen和maxlen1的长度,大的那个即是答案。
计算子串匹配时采用了Brute Force算法(存在着大量的重复运算,KMP算法可以提高匹配时效)。另外使用了一些字符串库函数,例如字符串长度函数strlen(),比较字符串大小的函数strcmp(),字符串复制函数strcpy()等。
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 5 char p[105][105]; 6 char reverse[105]; 7 char s[105]; 8 9 int main() 10 { 11 bool ok; 12 int t, n, i, j, k, l, len, maxlen, maxlen1; 13 while (cin >> t) 14 { 15 while (t--) 16 { 17 memset(s, 0, sizeof(s)); 18 cin >> n; 19 for (i = 0; i < n; i++) // 输入第i个序列 20 cin >> p[i]; 21 len = strlen(p[0]); 22 l = len - 1; 23 maxlen = maxlen1 = 0; // 最长公共子串的长度 24 for (i = 0; i < len; i++) // 枚举子串的起始位置i 25 { 26 reverse[l--] = p[0][i]; // 存放第一个序列的逆序列 27 for (j = i; j < len; j++) // 枚举子串的结束位置j
28 { 29 strncpy(s, p[0]+i, j-i+1); // 提取该子串s 30 s[j-i+1] = '\0'; 31 ok = true; // 试探s是否为p[1]...p[n-1]的公共子串 32 for (k = 1; ok && k < n; k++) 33 { 34 if (strstr(p[k], s) == 0) // 如果找到一条序列不是以当前s为子串,则枚举下一条新的子串s 35 ok = false; 36 } 37 if (ok && maxlen < j-i+1) // s是所有序列的公共子串,且s串的长度 > maxlen,则将maxlen调整为s串的长度 38 maxlen = j - i + 1; 39 } 40 } 41 for (i = 0; i < len; i++) // 第一个子串的逆序时的处理,与顺序时的处理相同 42 { 43 for (j = i; j < len; j++) 44 { 45 strncpy(s, reverse+i, j-i+1); 46 s[j-i+1] = '\0'; 47 ok = true; 48 for (k = 1; ok && k < n; k++) 49 { 50 if (strstr(p[k], s) == 0) 51 ok = false; 52 } 53 if (ok && maxlen1 < j-i+1) 54 maxlen1 = j - i + 1; 55 } 56 } 57 printf("%d\n", (maxlen1 > maxlen ? maxlen1 : maxlen)); // 比较顺序和逆序时哪个子串的长度大 58 } 59 } 60 return 0; 61 }