[ACM模板]AC自动机

#include<stdio.h>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;
#define ACMXNODE 110   //AC自动机节点数(最大为所有字符串字符个数和)
int charIdx(char ch){ return ch-'a'; }
#define CHARSIZE 128   //不同字符个数(128可以处理大部分情况,空间紧张可以减少这个值,但要保证charIdx每个字符都对应一个下标)
class ACAUTO{
private:
  int sz;
  int ch[ACMXNODE][CHARSIZE];
  int val[ACMXNODE];       //节点标记值,0表示非叶子节点。叶子节点记录一个自定义值(如是第几个字符串)。(相同字符串会互相覆盖)
  int f[ACMXNODE];         //fail数组
  int last[ACMXNODE];      last[u]:上一个u结尾的字符串。如有两个字符串(abcd,bc),节点u表示abc,则节点last[u]指向bc。
  int print(int i,int j);
public:
  ACAUTO();
  //初始化+建图
  int clearMap();          //初始化
  int ins(char *s,int v);  //插入一个字符串,v代表字符串结尾节点标记值。(0:非字符串结尾,其他:自定义)
  int getFail();           //建立失配指针。bfs查找
  int kmpFind(char *T);    //找出trie树中所有为T子串的字符串
};
ACAUTO::ACAUTO(){clearMap();}
int ACAUTO::clearMap(){
  sz=1;
  memset(ch[0],0,sizeof(ch[0]));
  memset(val,0,sizeof(val));
  return 0;
}
int ACAUTO::ins(char* s,int v=1){
  int u=0;
  int n=strlen(s);
  for (int i=0;i<n;i++){
    int c=charIdx(s[i]);
    if (!ch[u][c]){
      memset(ch[sz],0,sizeof(ch[sz]));
      val[sz]=0;
      ch[u][c]=sz++;
    }
    u=ch[u][c];
  }
  val[u]=v;
  return 0;
}
int ACAUTO::getFail(){
  queue<int> q;
  //先处理节点0的fail值
  f[0]=0;
  for (int c=0;c<CHARSIZE;c++){
    int u=ch[0][c];
    if (u){
      f[u]=0;q.push(u);last[u]=0;
    }
  }
  //处理其他节点
  while (!q.empty()){
    int r=q.front();q.pop();
    for (int c=0;c<CHARSIZE;c++){
       int u=ch[r][c];
       if (!u){ch[r][c]=ch[f[r]][c];continue;}
       q.push(u);
       f[u]=ch[f[r]][c];
       last[u]=val[f[u]]?f[u]:last[f[u]];
    }
  }
}

int ACAUTO::kmpFind(char *T){
  int n=strlen(T);
  int j=0;
  for (int i=0;i<n;i++){
    int c=charIdx(T[i]);
    j=ch[j][c];
    if (val[j])print(i,j);
      else
      if (last[j]) print(i,last[j]);
  }
}
int ACAUTO::print(int i,int j){
  if (j){
     printf("模板串T第%d个字符结尾子串和AC自动机编号为%d的一样,last[%d]=%d\n",i+1,val[j],j,last[j]);
     print(i,last[j]);
  }
  return 0;
}
ACAUTO ac;
int main(){
  int n;
  scanf("%d",&n);
  char s[100];
  ac.clearMap();
  for (int i=1;i<=n;i++){
    scanf("%s",s);
    ac.ins(s,i);
  }
  ac.getFail();
  while (1){
    scanf("%s",s);
    ac.kmpFind(s);
  }
  return 0;
}


1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An<O(N), O(1)> algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值