<题目链接>
题目大意:
就是求k个长度为60的字符串的最长连续公共子串,2<=k<=10
限制条件:
1、 最长公共串长度小于3输出 no significant commonalities
2、 若出现等长的最长的子串,则输出字典序最小的串
解题分析:
将第一个字串的所有子串枚举出来,然后用KMP快速判断该子串是否在所有主串中出现,如果都出现过,那么就按该子串的长度和字典序,不断更新答案,直到得到最终的最优解。
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <algorithm> using namespace std; const int maxn = 1100; char a[maxn]; char b[maxn]; int next0[maxn]; char s[15][maxn]; void find_next() { int len = strlen(b); int k = -1; next0[0] = -1; int j = 0; while (j < len - 1) { if (k == -1 || b[j] == b[k]) { next0[++j] = ++k; } else k = next0[k]; } } int kmp() { int i = 0, j = 0; int alen = strlen(a); int blen = strlen(b); while (i < alen&&j < blen) { if (j == -1 || a[i] == b[j]) { i++; j++; } else j = next0[j]; } if (j == blen)return i - j + 1; return -1; } int main() { int t; scanf("%d", &t); while (t--) { int n; scanf("%d", &n); getchar(); for (int i = 0; i < n; i++) { scanf("%s", &s[i]); } int len = strlen(s[0]); int cnt = 0; char ans[maxn]; for (int i = 0; i < len; i++) { for (int j = 1; j <= len - i; j++) { for (int k = 0; k < j; k++) b[k] = s[0][i + k]; b[j] = '\0'; find_next(); bool flag = true; for (int k = 1; k < n; k++) { strcpy(a, s[k]); if (kmp() == -1) { flag = false; break; } } if (flag) //如果该子串为所有主串的公共子串 { int lenng = strlen(b); if (j > cnt&&lenng >= 3) //cnt为最长公共子串的长度 { cnt = j; strcpy(ans, b); //ans储存的是最终符合要求的最长公共子串 } if (j == cnt && strcmp(ans, b) > 0)strcpy(ans, b); //按字典序更新与当前最长公共子串长度相同的公共子串 } } } if (cnt == 0)printf("no significant commonalities\n"); else printf("%s\n", ans); } return 0; }
2018-08-07