POJ3450最长公共子串【kmp】
题目链接:http://poj.org/problem?id=3450
题目大意:给定n个长度不超过200的字符串,n < 4000。求这些字符串的最长公共子串,若没有,则输出 “IDENTITY LOST”。
思路:
1.枚举第一个字符串的各个子串s,将s分别与其他字符串进行kmp,来找到可以取得的s的最大长度(这样就是一次枚举中所有字符串的公共子串),然后接着枚举子串s,更新这个长度,注意在长度相等时选取字典序小即可。
2.strcmp(a, b)比较a, b字符串,返回值为0则字符串相同。返回值大于0则a的字典序大于b的字典序,返回值小于0则a的字典序小于b的字典序。
3.strcpy(a, b)将b字符串复制给a,strncpy(a, b, len)将b字符串前len个长度的字符复制给a,注意需要手动给a添加结束符 '\0'.
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 const int inf = 0x3f3f3f3f; 5 using namespace std; 6 7 char str[4100][210], s[210], res[210], tt[210]; 8 int next[210], temp, s_len, str_len, flag; 9 10 void get_next() 11 { 12 s_len = strlen(s);//模式串 13 next[0] = -1; 14 int j = 0, k = -1; 15 while(j < s_len) 16 { 17 if(k == -1 || s[j] == s[k]) 18 { 19 j ++, k ++; 20 next[j] = k; 21 } 22 else 23 k = next[k]; 24 } 25 } 26 27 void kmp(int id) 28 { 29 temp = 0; 30 str_len = strlen(str[id]); 31 int i = 0, j = 0; //i文本串 j模式串 32 int vis = 0; 33 while(i < str_len && j < s_len) 34 { 35 if(s[j] == str[id][i] || j == -1) 36 { 37 vis = 1; 38 i ++, j ++; 39 } 40 else 41 j = next[j]; 42 temp = max(temp, j); 43 } 44 if(!vis) 45 flag = 0; 46 } 47 48 int main() 49 { 50 int n, minn, ans_len, xx; 51 while(scanf("%d", &n) != EOF) 52 { 53 if(n == 0) 54 break; 55 getchar(); 56 ans_len = -1; 57 for(int i = 0; i < n; i ++) 58 scanf("%s", str[i]); 59 int len = strlen(str[0]); 60 for(int i = 0; i < len; i ++) 61 { 62 minn = inf, xx = 0; 63 strcpy(s, str[0] + i); 64 get_next(); 65 flag = 1; 66 for(int j = 1; j < n; j ++) 67 { 68 kmp(j); 69 if(flag == 0) 70 { 71 xx = 1; 72 break; 73 } 74 minn = min(minn, temp); 75 } 76 if(xx == 1) 77 continue; 78 if(minn > ans_len) 79 { 80 ans_len = minn; 81 strncpy(res, s, ans_len); 82 res[ans_len] = '\0'; 83 } 84 if(minn == ans_len) 85 { 86 strncpy(tt, s, minn); 87 tt[minn] = '\0'; 88 if(strcmp(res, tt) > 0) 89 strcpy(res, tt); 90 } 91 } 92 if(ans_len == 0 || ans_len == -1) 93 printf("IDENTITY LOST\n"); 94 else 95 printf("%s\n", res); 96 } 97 return 0; 98 }