后缀自动机SAM

来源:互联网 发布:阿里云域名解析端口号 编辑:程序博客网 时间:2024/06/06 02:44
#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<algorithm>#include<map> using namespace std ;const int maxn = 1e5 ;struct state{    //step代表从root(就是0)到当前点的最长路径     //pre 代表当前节点的转移的前一个节点     int step , pre ;    //map表示当前节点的转移的边,char 代表输入char字符,就转移到了int节点处     map<char , int> next ; };  state st[maxn * 2] ;//last表示当前字符串的最后一个字符所代表的节点的位置//sz扩充节点 int last , sz ;void init(){    //初始化     sz = last = 0 ;    //根节点rot     st[0].step = 0 ;    st[0].pre = -1 ;    sz++ ;    for( int i = 0 ;i<maxn* 2 ;i++)        st[i].next.clear() ;}//添加字符c void SAMEXT( char c ){    //增加一个节点表示当前节点     int cur = sz ++ ;    //当前节点的长度     st[cur].step = st[last].step + 1 ;    //p从last开始不断往上走,p和当前节点建立连接实边,直到走到根节点p=-1 或者一个节点的子节点包含c字符     int p ;    for( p = last ; p != -1 && !st[p].next.count(c) ; p = st[p].pre)        st[p].next[c] = cur ;    //如果走到根节点则当前节点的pre指针指向根节点    if( p == -1 )        st[cur].pre = 0 ;    //否则分两种情况    else{        //令p节点的c子节点为p         int q = st[p].next[c] ;        //如果q节点最长由p转移得到,则当前节点的pre指向q节点        //否则重新建立一个q节点连接到p节点使得step相差1         if( st[p].step +1 == st[q].step )            st[cur].pre = q ;        else{            int clone = sz ++ ;            st[clone].step = st[p].step + 1;            st[clone].next = st[q].next ;            st[clone].pre = st[q].pre ;            //p继续往上走,对于p节点由q节点的p节点,将他的指向q节点的指针指向新建的clone节点            for( ; p != -1 && st[p].next[c] == q ; p = st[p].pre )                st[p].next[c] = clone ;            //q节点和cur节点的pre邹瑶指向clone节点             st[q].pre = st[cur].pre = clone ;         }    }     //last 扩充大cur    last = cur ; }string s( "ACADD" ) ;char temp[maxn] ;void dfs( int x ,int y){    for(int i = 0 ;i< y ;i++)           cout<<temp[i] ;    cout<<endl;    for( map<char, int>::iterator it = st[x].next.begin() ; it != st[x].next.end() ; it++){        temp[y] = it->first ;        dfs( it->second , y+ 1) ;    }}int main(){    //初始化    init() ;     //构造后缀自动机     for(int i = 0 ;i< s.size() ;i++)        SAMEXT(s[i]) ;    //输出后缀自动机    cout<<"输出后缀自动机"<<endl;     for(int i = 0 ;i< sz ;i++){        for( map<char, int>::iterator it = st[i].next.begin() ; it != st[i].next.end() ; it++){            cout<<it->first<<it->second<<" ";        }               cout<<endl;    }       cout<<endl;    //DFS 显示后缀自动机的所有子串    cout<<"DFS 显示后缀自动机的所有子串"<<endl;    dfs( 0 , 0) ;    return 0 ; }
原创粉丝点击