SPOJ LCS2 多个串的最长公共子串

 这里串最多有10个,找所有串的最长公共子串

这里后缀自动机做,以第一个串建立后缀自动机,后面的串一个个去匹配,每次得到当前串在可到达状态上所能得到的最长后缀长度

拿所有串匹配后得到的结果进行计算

 

 1 #include <iostream>

 2 #include <cstdio>

 3 #include <cstring>

 4 using namespace std;

 5 #define M 26

 6 #define N 200100

 7 char str[N];

 8 struct SamNode{

 9     SamNode *son[M] , *f;

10     int l , nc , c;

11 }sam[N] , *last , *root , *b[N];

12 

13 int cnt , num[N];

14 

15 void init()

16 {

17     root = last = &sam[cnt=0];

18 }

19 

20 void add(int x)

21 {

22     SamNode *p = &sam[++cnt] , *jp=last;

23     p->l = jp->l+1 , p->nc = p->l;

24     last = p;

25     for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x]=p;

26     if(!jp) p->f = root;

27     else{

28         if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];

29         else{

30             SamNode *r = &sam[++cnt] , *q = jp->son[x];

31             *r = *q;

32             r->l = r->nc = jp->l+1;

33             q->f = p->f = r;

34             for( ; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r;

35         }

36     }

37 }

38 

39 void solve()

40 {

41     int len = strlen(str) , ret;

42     for(int i=0 ; i<=cnt ; i++) num[sam[i].l]++;

43     for(int i=1 ; i<=len ; i++) num[i]+=num[i-1];

44     for(int i=0 ; i<=cnt ; i++) b[--num[sam[i].l]] = &sam[i];

45     while(~scanf("%s" , str)){

46         len = strlen(str) , ret=0;

47         SamNode *cur = root;

48         for(int i=0 ; i<len ; i++){

49             int x = str[i]-'a';

50             if(cur->son[x]){

51                 ret++;

52                 cur = cur->son[x];

53             }

54             else{

55                 while(cur && !cur->son[x]) cur = cur->f;

56                 if(!cur){

57                     cur = root;

58                     ret = 0;

59                 }else{

60                     ret = cur->l+1;

61                     cur = cur->son[x];

62                 }

63             }

64             cur->c = max(cur->c , ret);

65         }

66         for(int i=cnt ; i>0 ; i--){

67             b[i]->nc = min(b[i]->nc , b[i]->c);

68             //子节点可接受到的后缀父节点必定能够接收到,反之却不一定

69             b[i]->f->c = max(b[i]->f->c , b[i]->c);

70             b[i]->c = 0;

71         }

72     }

73 }

74 

75 int main() {

76 //    freopen("a.in" , "r" , stdin);

77     scanf("%s" , str);

78     init();

79     int len = (int)strlen(str);

80     for(int i=0 ; i<len ; i++) add(str[i]-'a');

81     solve();

82     int ret = 0;

83     SamNode *cur;

84     for(int i=1 ; i<=cnt ; i++){

85         cur = &sam[i];

86         ret = max(cur->nc , ret);

87     }

88     printf("%d\n" , ret);

89     return 0;

90 }

 

你可能感兴趣的:(poj)