AC自动机小试 POJ2778

来源:互联网 发布:电脑软件怎么清除数据 编辑:程序博客网 时间:2024/05/18 03:39

http://poj.org/problem?id=2778

题目翻译:给定m个异常基因片段,在所有长度为N的DNA序列中如‘AAAAA....’,'ATTTTT....','ATCG...','CGTA...',.....中不包含异常序列的DNA个数mod 100000(十万)的值

这题题解是AC自动机和矩阵乘法,首先建立AC自动机

我们先看AC自动机建立过程(会的跳过,不会的英语好的看这篇英文论文:http://wenku.baidu.com/view/8b6f6d85ec3a87c24028c467.html,不会的英文不好的看不懂论文的往下看)

首先定义node为记录类型

{   son[1..4]of int;code:char;fail:longint;danger:boolean;

    son,fail初始为-1或nil或null,danger:=false;

     }

定义函数

function anti(a:char):longint;

begin  case a of

            'A':exit(1);
        'C':exit(2);
        'G':exit(3);
        'T':exit(4);
        end;

end;

1.建立Trie树,即字母树

2.初始化第一层节点fail指针为root节点,将第一层节点加入队列中

3.取队首元素x,将所有x的son入队

4.for y ∈ x.son

       begin

            temp:=x.fail;

            while (temp>0)or(temp<>root) do

                 begin

                     for z ∈ temp.son

                        if z.code=y.code

                           then flag:=true,break;

                     if flag then temp:=z,break;

                     temp:=temp.fail;

                 end;

           if  temp=root

             then

                  for z ∈ root.son

                        if z.code=y.code

                           then temp:=z,break;

            y.fail:=temp;

       end;

5.Complete Build AC Automaton

注意到一个经典的矩阵乘法题,给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值

答案是将有向图的邻接矩阵乘k次输出G[A,B]

我们可以把A点看做root点,走n步不经过异常节点的方案数mod p(p=100000)的值

那么很明显一点是x节点的son中的异常节点(设为y)是不可能由x转移到的

题中每个节点最多有4个son

如果某个x.son为nil呢

设z=x.fail,当前son为i

由于x.fail为x.son匹配失败时的最长后缀在trie中的位置,那么以fail指针往上(fail指针总是指向上面)寻找z.son[i]不为nil的z节点后终止

然后判断z.son[i]是否为异常节点,不是则g[x,z.son[i]]++或者若z=root且root.son[i]=nil 则g[x,root]++;

按照trie的bfs序列

取当前元素x

for i:=1 to 4 do

  if x.son[i]=-1

    then

      begin

            z:=x.fail

            while (z<>root)and(z.son[i]=-1) do

                 z:=z.fail;

            if  (z=root)and(root.son[i]=-1)

              then g[x,root]++

             else

                if   (z.son[i]<>-1)and(not z.son[i].danger)

                  then g[x,z.son[i]]++;

      end

   else if  not x.son[i].danger then g[x,x.son[i]]++;        

然后就是将g矩阵乘n次,将第root行加起来mod 100000 就是ans

代码pascal

program poj2778;type    matrix=array[0..101,0..101]of int64;const   mo=100000;var     a:string;nodes,leng,i,j,point,m,n,top,x,tail,som,k:longint;ans:int64;        b,g:matrix;        son:array[0..101,0..4]of longint;        off:array[0..101]of longint;        code:array[0..101]of char;        stack:array[0..110]of longint;        comp:array[0..110]of boolean;procedure muti(a,b:matrix;var c:matrix);begin   fillchar(c,sizeof(c),0);        for i:=0 to nodes do          for j:=0 to nodes do            begin              for k:=0 to nodes do                c[i,j]:=(a[i,k]*b[k,j]+c[i,j])mod mo;            end;end;function anticode(a:char):longint;begin   case a of        'A':exit(1);        'C':exit(2);        'G':exit(3);        'T':exit(4);        else exit(0);        end;end;begin        readln(m,n);        fillchar(son,sizeof(son),$ff);        for i:=1 to m do          begin            readln(a);            leng:=length(a);            point:=0;            for j:=1 to leng do              begin                if son[point,anticode(a[j])]<>-1                  then                    point:=son[point,anticode(a[j])]                  else                    begin                      inc(nodes);                      son[point,anticode(a[j])]:=nodes;                      code[nodes]:=a[j];                      point:=nodes;                    end;              end;            comp[point]:=true;          end;        top:=0;        tail:=1;        while top<tail do          begin            inc(top);            x:=stack[top];            for i:=1 to 4 do              if son[x,i]<>-1                then                  begin                    inc(tail);                    stack[tail]:=son[x,i];                    if x=0 then continue;                    som:=off[x];                    repeat                      if son[som,i]<>-1                        then                          begin                            som:=son[som,i];                            break;                          end;                      som:=off[som];                    until som<=0;                    if som=0                      then                        if son[som,i]<>-1                          then                            som:=son[som,i];                    if comp[som]                      then comp[son[x,i]]:=true;                    off[son[x,i]]:=som;                  end;          end;        top:=0;nodes:=0;        while top<tail do          begin            inc(top);            x:=stack[top];            if comp[x] then continue;            if x>nodes then nodes:=x;            for i:=1 to 4 do              if son[x,i]=-1                then                  begin                    som:=off[x];                    while (som>0)and(son[som,i]=-1) do                      begin                        som:=off[som];                      end;                    if (son[som,i]<>-1)and(not comp[son[som,i]])                      then                        inc(g[x,son[som,i]])                      else                        if (som=0)and(son[som,i]=-1)                          then                            inc(g[x,0]);                  end                else                  if (son[x,i]<>-1)and(not comp[son[x,i]])                    then                      inc(g[x,son[x,i]]);          end;        for i:=0 to nodes do          b[i,i]:=1;        while (n>0) do          begin            if (n and 1)>0              then                muti(b,g,b);            n:=n>>1;            muti(g,g,g);          end;        for i:=0 to nodes do          ans:=(ans+b[0,i])mod mo;        writeln(ans);end.

另一篇题解:http://hi.baidu.com/%D2%D5%C1%D6010/blog/item/6db06ccf0a3b440993457e7b.html

原创粉丝点击