suffix automachine-陈立杰讲稿学习笔记

来源:互联网 发布:淘宝宝贝分类源代码 编辑:程序博客网 时间:2024/05/17 05:11

    在回答什么是suffix auto machine前我们需要先知道什么是auto machine。

    什么是自动机?一个FSN(有限状态自动机)就是一个具有识别字符串S对于自动机A是true还是false;即当s属于alpha,判断trans(state,ch)是否等于end;

    同时令trans(state,str)表示当前状态是s,在读入字符串str之后,所到达的状态。
    而一个sam就是一个能够识别字符s所有后缀的自动机。
    我们可以像AC自动机一样,在trie上建立sam,但显然对于长度为N的串可能有N^2个结点;能不能优化呢?
    我们可以先空想一个假设存在一个叫最简状态后缀机的东西,在还没有构造出这个东西前我们可以先看看它会有什么性质。
    设有一母串S,它的所有后缀集合为suf,设从a开始的后缀为suffix(a),定义st(str)=trans(init,str),reg(st(a))为st(a)能识别出的字符串集;
    性质一:若串s不属于suf则st(s)=null;
    性质二:若串s属于suf则st(s)!=null;
    推论1:x能被自动机识别当且仅当x属于suf;
    推论2:st(a)能识别x当且仅当ax属于suf;
    推论3:如果a在s的范围为【l,r)则st(a)能识别S从r开始的后缀;
    推论4:如果a在s的范围集合为【L1,R1),【L2,R2),【L3,R3)。。。【Ln,Rn),则st(a)能识别以R1,R2,R3.。。Rn开始的后缀,设right(a)={R1,R2,R3...Rn};
    性质三:若对两个串a,b属于fac,且right(a)=right(b),则st(a)=st(b),所以状态s可以简化为所有right集合为right(s)的串的公共母串;
    性质四:若r属于right(s),且已知子串长度len,则该子串为S【r-len,r),且显然长度len的可选范围为一个区间,则可令s的区间为【min(s),max(s)】;
    这时最简状态后缀机的线性性就显然了;
    而我们可以用简化后的right集合构建一颗树,不妨取名parent,则显然max(fa(s))=min(s)-1;
    显然以转移方式建树的边也不会超过o(n);
    由于父亲的right集是它的后代的所有right集的并集,所以我们可以用树的dfs序排列建树;
    下面是kuangbin的后缀自动机板子;
    

structSAM_Node
{

SAM_Node*fa,*next[CHAR];intlen;
intid,pos;
SAM_Node(){}

SAM_Node(int_len){

fa= 0;
len= _len;memset(next,0,sizeof(next));

}};

SAM_NodeSAM_node[MAXN*2], *SAM_root, *SAM_last;intSAM_size;
SAM_Node*newSAM_Node(intlen)
{

SAM_node[SAM_size] =SAM_Node(len);SAM_node[SAM_size].id= SAM_size;return&SAM_node[SAM_size++];

}
SAM_Node*newSAM_Node(SAM_Node*p){

SAM_node[SAM_size] = *p;SAM_node[SAM_size].id= SAM_size;return&SAM_node[SAM_size++];

}
voidSAM_init(){

SAM_size = 0;
SAM_root = SAM_last = newSAM_Node(0);SAM_node[0].
pos= 0;

}
voidSAM_add(intx,intlen){

SAM_Node*p = SAM_last, *np = newSAM_Node(p->len+1);np->pos= len;
SAM_last = np;
for(;p && !p->next[x];p = p->fa)p->next[x] = np;

if(!p){

np->fa= SAM_root;

return;}

SAM_Node*q = p->next[x];if(q->len== p->len+ 1){

np->fa= q;

return;}

SAM_Node*nq = newSAM_Node(q);nq->len= p->len+ 1;
q->
fa= nq;
np->
fa= nq;

for(;p && p->next[x] == q;p = p->fa)p->next[x] = nq;

}
voidSAM_build(char*s){

SAM_init();
intlen =strlen(s);for(inti = 0;i < len;i++)

SAM_add(s[i] -'a',i+1);

}

//加入串后进行拓扑排序。charstr[MAXN];
inttopocnt[MAXN];SAM_Node*topsam[MAXN*2];

intn =strlen(str);SAM_build(str);memset(topocnt,0,sizeof(topocnt));for(inti = 0;i < SAM_size;i++)

topocnt[SAM_node[i].len]++;for(inti = 1;i <= n;i++)

topocnt[i] += topocnt[i-1];for(inti = 0;i < SAM_size;i++)

topsam[--topocnt[SAM_node[i].len]] = &SAM_node[i];


   
  好了。。。拜拜~~
   
   


原创粉丝点击