后缀自动机SAM

终于遇到了一道后缀数组不能过 一定要学SAM的题。。。

(看了半个下午+半个上午)

现在总结一下(是给我自己总结。。所以只总结了我觉得重要的 。。

看不太懂的话可以To   http://blog.csdn.net/clover_hxy/article/details/53758535  图文并茂

或者 去看更长更详细的陈立杰PPT   http://wenku.baidu.com/link?url=9YEHHchtr0vyGGDZAcsMYPI3l_Q82UNPuS4KqkfrlG_t5NFk_9iXZd86Uq4uDqqLUKFJL7ZINkxQbstwqaF6OEFes3elFsXmbDZVIsgVwti:

SAM   Suffix AutoMaton    [AutoMaton的定义 不懂自己查吧 ]

首先  (N为 字符串长度*2)  最基本的SAM 要开的数组 (其含义与用处在之后说明):pr[N] (别人的代码版本还有fa、pre、link...变量名而已 别在意), ch[N][26(当然不一定是26个字母)],

ma[N](意思是maxlen,别人的有step、len...),还要cnt和last两个全局变量,p,np,q,nq 四个局部变量。 root就设为1,所以不需要开个变量rt。

SAM为什么能用O(n)的空间存下n^2的子串? 我是这样理解的{

  每个节点 对应的是 一个独一无二的right集合

    right集合是什么?【比如说 一个S字符串为 AABABA  ,子串BA有2个 对吧 .所有子串BA 对应的右端点集合(即right集合)为{4,6},子串ABA也有2个 ,right集合也是{4,6}】

    那么 BA和ABA的right集合一样 BA和ABA 被自动机从rt状态 一步一步转移 最终到达同一个节点

  设这个节点 编号为v,v不仅对应了 {4,6}这个right集合 同时还对应了 子串BA和ABA     可以看出 v代表的子串  其右端点是 同时属于 集合{4,6}的 【什么叫同时属于? 看看AABA,它的右端点只能是4,不能是6】,还可以看出 只有长度为2~3的子串可以 满足“同时属于”  ,【如长度为1的A, 它不仅属于{4,6} 它属于{1,2,4,6};  长度为4的AABA,它只属于{4}——————所以它们属于另外的节点】

这里长度为2~3可能不是很明显 但其实可行的长度 一定是连续的min~max  想想就明白了。。

  [v节点对应 的子串 长度为min(v)~max(v)] 这个信息由 ma[]存储,ma[v]=max(v)  但它只存储了最大值。 最小值呢? [这里先提一下 ,min(v)   是 ma[pr[v]]+1,接下来会说。。

  那么我们来证明节点数是 O(N)的  (准确说是 小于 length(S)*2)

  先来看 上面那个字符串AABABA , 对它建出的SAM有  个节点,通过pr[] 构成一棵树,最好在草稿纸上画个图

     以下一一说明:

  1号  即root节点(我简写成rt) 对应right集合{1,2,3,4,5,6}  长度是 0~0   pr[1]=0

以下x号只是我给节点标个号,可能真正的数组下标不是这样的,不要在意,但1号一定是1。

  2号  {1,2,4,6}  长度是 1~1  对应子串:A,A,A,A   pr[2]=1

  3号  {3,5} 长度1~2   pr[3]=1   对应:B,B,AB,AB

  4号  {2}  长度2~2     pr[4]=2    对应:AA

  5号  {4,6} 长度2~3   pr[5]=2    对应:BA,BA,ABA,ABA

  6号  {3} 长度3~3      pr[6]=3    对应:AAB

  7号  {5} 长度3~5      pr[7]=3    对应:BAB,ABAB,AABAB

  8号  {4} 长度4~4      pr[8]=5    对应:AABA

  9号  {6} 长度4~6      pr[9]=5    对应:BABA,ABABA,AABABA

  从根到叶子 就是对集合{1,2,...,n}不断地分割成至少两个部分

  可以看出来

    *叶子节点最多n个 而且每个非叶子节点都有分叉导致right集合不断变小 所以显然空间是O(N)的

    *再数一下  对应的子串 总共是 6*(6+1)/2=21个,它们包含了S的所有子串

    *对于一个节点v,它的right集合有k个元素,长度范围是min(v)~max(v)

    *观察 min(v)=ma[pr[v]]+1 这条性质,好好理解一下  长度越小的串在S中出现次数越多   所以right集合越大,

  所以  从根到叶子 的right集合不断变小,而min和max在增加。。      这样就明白pr[]是什么了吧。

}

那么现在讲 ch[v][c],挺好理解 ,就是 从v节点 再读入一个c字符(字符已经转成int了)之后会转移到 的节点

所有节点有ch[v][c]构成一个拓扑图  注意 这个拓扑图的结构 与pr[]连成的树 毫无关联。 只是两者之间满足了一些性质(之后讲)

先上一下代码  对字符串S建出SAM  (是一个字符一个字符添加的)

 1  void add(int c){
 2         int p,np,q,nq;
 3      p=last; last=np=++cnt; ma[np]=ma[p]+1;
 4      while (!ch[p][c]&&p) ch[p][c]=np,p=pr[p];
 5      if (!p) pr[np]=1; else{
 6          q=ch[p][c];
 7          if (ma[p]+1==ma[q]) pr[np]=q;
 8          else{
 9              nq=++cnt; ma[nq]=ma[p]+1;
10              pr[nq]=pr[q]; pr[q]=pr[np]=nq;
11              memcpy(ch[nq],ch[q],sizeof ch[q]);
12              while (ch[p][c]==q) ch[p][c]=nq,p=pr[p];
13          }
14      }
15  }

不知道前面说的清不清楚 但是看到这段代码 大多数人第一反应 应该是一脸懵逼的。。

现在我来(对着一些语句)解答疑问(如果你疑问很多 不要像我一样死钻一个问题。 你可以先看完,然后说不定就能解决前面的疑问):

  &  cnt,last是全局变量,cnt就是计数,不多说。。last(之前忘记提了)是上一次add操作后,加入的那个节点(注意不一定是cnt-1);

  &

...今天先写到这里、、、好累。。。

时间: 2024-12-13 14:44:53

后缀自动机SAM的相关文章

浅谈后缀自动机SAM

一下是蒟蒻的个人想法,并不很严谨,仅供参考,如有缺误,敬请提出 参考资料: 陈立杰原版课件 litble 某大神 某大神 其实课件讲得最详实了 有限状态自动机 我们要学后缀自动机,我们先来了解一下自动机到底是什么.[虽说以前也学过AC自动机,只是当一个名字罢了] 有限自动机的功能是识别字符串,作用各不相同 如果自动机A能识别串s,那么A(s) = true 自动机有一个初始状态,从初始状态出发能到达多个状态.到达终止状态表示字符串识别 后缀自动机SAM 我们略去建机原理的分析和建机过程,具体原理

后缀自动机(SAM) 合集

先上模板 int len[maxn << 1],fa[maxn << 1],son[maxn << 1][maxc]; LL num[maxn << 1]; int size,last; void Init(){ size = last = 1; } void insert(char c){ int s = c - 'a'; int p = last,np = ++size;last = np; num[np] = 1; //主链结点出现次数 + 1 len

【文文殿下】后缀自动机(SAM)求最长公共子串的方法

首先,在A 串上建立一个SAM,然后用B串在上面跑.具体跑的方法是: 从根节点开始,建立一个指针 p ,指着B串的开头,同步移动指针,沿着SAM的边移动,如果可以移动(即存在边)那么万事皆好,直接len++就好,但是,如果无法继续转移(失配了),那么,我们考虑跳回其父节点,因为其父节点的Right集是当前状态的真超集,那么其父节点状态所代表的字符串的集合中的任意一个字符串,都是当前状态所代表的字符串集合中的正在匹配的字符串(会不会一定是最长串?)的后缀,所以,有一个贪心的思想:父节点状态中的最长

后缀自动机(SAM) :SPOJ LCS - Longest Common Substring

LCS - Longest Common Substring no tags A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a consecutive sequence of characters occurrences at

后缀自动机(SAM)模板

1 struct SAM{ 2 int ch[maxn][26],fa[maxn],len[maxn],cnt,last; 3 void Init() 4 { 5 memset(ch,0,sizeof(ch)); 6 memset(fa,0,sizeof(fa)); 7 last=cnt=1; 8 } 9 void Add(int c) 10 { 11 int p=last,np=last=++cnt; 12 len[np]=len[p]+1; 13 while(!ch[p][c]&&p)

[hdu4436 str2int]后缀自动机SAM(或后缀数组SA)

题意:给n个数字串,求它们的所有不包含前导0的不同子串的值之和 思路:把数字串拼接在一起,构造SAM,然后以每个状态的长度len作为特征值从小到大排序,从前往后处理每个状态,相当于按拓扑序在图上合并计算答案. #include <bits/stdc++.h> using namespace std; #define X first #define Y second #define pb(x) push_back(x) #define mp(x, y) make_pair(x, y) #defi

后缀自动机(SAM):SPOJ Longest Common Substring II

Longest Common Substring II Time Limit: 2000ms Memory Limit: 262144KB A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a consecutive sequenc

[bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)

偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1943  Solved: 1004[Submit][Status][Discuss] Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的01串,表示N篇作文 Output N行,每行一个整数,表示这篇作文的Lo

[转]后缀自动机

原文地址:http://blog.sina.com.cn/s/blog_8fcd775901019mi4.html 感觉自己看这个终于觉得能看懂了!也能感受到后缀自动机究竟是一种怎样进行的数据结构了... 笔者自己的话会用楷体表示出来...[说不定能帮助大家理解,但是可能也破坏了大家的自主理解力?所以...看不懂的话再来看好咯...] 常用的字符串处理工具: 1.       整词索引:排序+二分:Hash表.可以解决整词匹配,但不支持前缀搜索:Hash表在模式串定长的情况下可以用RK解决多模式