ac自动机和有限状态.docx
- 文档编号:26565587
- 上传时间:2023-06-20
- 格式:DOCX
- 页数:23
- 大小:20.50KB
ac自动机和有限状态.docx
《ac自动机和有限状态.docx》由会员分享,可在线阅读,更多相关《ac自动机和有限状态.docx(23页珍藏版)》请在冰豆网上搜索。
ac自动机和有限状态
POJ1204(AC自动机模板题)
题意:
给一个N行长为M的字符串,给你一些需要去匹配的字符串,从任意一个字符串开始可以有八个方向,向上为A,顺时针依次是A——H,问你去匹配的字符串在给你的N*M字符串中的坐标是怎么样的。
代码:
constmaxnodes=500000;
varfx:
array[1..8]ofchar=('E','F','G','H','A','B','C','D');
t:
array[0..maxnodes,'A'..'Z']oflongint;
f,q,w:
array[0..maxnodes]oflongint;
e:
array[0..1001,0..1001]ofchar;
s:
array[0..1001]ofchar;
colu,line:
array[0..1]oflongint;
done:
array[0..1001]ofboolean;
ans:
array[0..1001]ofrecordx,y,f:
longint;end;
n,m,num,u,i,j,k,l,r,root,size,x,y,p,li,co,tmp,len:
longint;
c:
char;
functionnx(varx,y:
longint;f:
longint):
char;
begin
casefof
1:
dec(x);
2:
begindec(x);inc(y);end;
3:
inc(y);
4:
begininc(x);inc(y);end;
5:
inc(x);
6:
begininc(x);dec(y);end;
7:
dec(y);
8:
begindec(x);dec(y);end;
end;
if(x<1)or(x>n)or(y<1)or(y>m)thenexit('!
');
exit(e[x,y]);
end;
begin
readln(n,m,num);
line[0]:
=1;
line[1]:
=n;
colu[0]:
=1;
colu[1]:
=m;
fori:
=1tondo
begin
forj:
=1tomdoread(e[i,j]);
readln;
end;
root:
=0;
size:
=0;
fori:
=1tonumdo
begin
len:
=0;
whilenoteolndo
begin
inc(len);
read(s[len]);
end;
p:
=root;
forj:
=lendownto1do
begin
c:
=s[j];
ift[p][c]=0then
begin
inc(size);
t[p][c]:
=size;
end;
p:
=t[p][c];
end;
w[p]:
=i;
readln;
end;
l:
=0;
r:
=0;
forc:
='A'to'Z'do
ift[root][c]<>0then
begin
inc(r);
q[r]:
=t[root][c];
f[q[r]]:
=root;
end;
whilel begin inc(l); u: =q[l]; forc: ='A'to'Z'do ift[u][c]<>0then begin inc(r); q[r]: =t[u][c]; p: =f[u]; while(p<>root)and(t[p][c]=0)dop: =f[p]; f[q[r]]: =t[p][c]; end; end; fork: =1to8do forli: =0to1do forco: =1tomdo begin x: =line[li]; y: =co; p: =root; c: =e[x,y]; whiletruedo begin while(p<>root)and(t[p][c]=0)dop: =f[p]; p: =t[p][c]; tmp: =p; whiletmp<>rootdo begin if(w[tmp]>0)and(notdone[w[tmp]])then begin ans[w[tmp]].x: =x; ans[w[tmp]].y: =y; ans[w[tmp]].f: =k; done[w[tmp]]: =true; end; tmp: =f[tmp]; end; c: =nx(x,y,k); ifc='! 'thenbreak; end; end; fork: =1to8do forco: =0to1do forli: =1tondo begin x: =li; y: =colu[co]; p: =root; c: =e[x,y]; whiletruedo begin while(p<>root)and(t[p][c]=0)dop: =f[p]; p: =t[p][c]; tmp: =p; whiletmp<>rootdo begin if(w[tmp]>0)and(notdone[w[tmp]])then begin ans[w[tmp]].x: =x; ans[w[tmp]].y: =y; ans[w[tmp]].f: =k; done[w[tmp]]: =true; end; tmp: =f[tmp]; end; c: =nx(x,y,k); ifc='! 'thenbreak; end; end; fori: =1tonumdowriteln(ans[i].x-1,'',ans[i].y-1,'',fx[ans[i].f]); end. 2、密码破译 【问题描述】 由于最近功课过于繁忙,Tim竟然忘记了自己电脑的密码,幸运的是Tim在设计电脑密码的时候,用了一个非常特殊的方法记录下了密码。 这个方法是: Tim把密码和其它的一些假密码共同记录在了一个本子上面。 为了能够从这些字符串中找出正确的密码,Tim又在另外一个本子上面写了一个很长的字符串,而正确的密码就是在这个字符串中出现次数最多的一个密码。 例如串ababa,假若密码是abab和aba,那么正确的密码是aba,因为aba在这个字符串中出现了2次。 现在你得到了Tim的这两个本子,希望你能够编写一个程序帮助Tim找出正确的密码。 【输入】 输入由两个部分组成。 其中第一部分由若干行(<=5000)组成,每一行记录了一个密码,密码的均长度小于等于255位,并且都由小写字母组成。 然后一个空行,第二部分记录了一个很长的字符串,并且以’.’结束,其中只包含了小写字母。 【输出】 输出文件名为Pass.out。 输出文件由仅有一行,为一个整数,表示正确密码在字符串中出现的次数。 如果这个出现次数为0,输出“Nofind”。 【样例】: Pass.inPass.out ab6 abc bdc abcd abcabcabcdbdabcbabdbcabdbdbdbd. 程序: programpass; type point=^rec; rec=record a: array['a'..'z']ofpoint; e: {array[0..100]of}longint; fail,f: point; end;//这个是AC的数据结构,本人喜欢用动态 int=longint;//这个是个人习惯 var h,p,q: point; queue: array[1..200000]ofpoint; i,j,k,m,n: int; f: array[1..6000]ofint; st: ansistring; procedureneew(varP,father: point);//新建节点 var ch: char; begin new(p); p^.e: =-1; forch: ='a'to'z'dop^.a[ch]: =nil; p^.f: =father; end; procedureinsert(pos: int;st: ansistring);//插入 var i,l: int; begin p: =h;i: =1;l: =length(st); while(i<=l)and(p^.a[st[i]]<>nil)dobegin p: =p^.a[st[i]]; inc(i); end; ifi>lthenbegin p^.e: =pos; exit; end; while(i<=l)dobegin neew(p^.a[st[i]],p); p: =p^.a[st[i]]; inc(i); end; p^.e: =pos; end; procedurebuild;//建立字典树 begin readln(st); n: =0; neew(h,h); while(st<>'')dobegin inc(n); insert(n,st); readln(st); end; end; procedurefailure;//构建失败指针 var ch: char; i,p,q: longint; k: point; procedurefailure;//构建失败指针 var ch: char; i,p,q: longint; k: point; begin h^.fail: =h;p: =1;q: =0; forch: ='a'to'z'do if(h^.a[ch]<>nil)thenbegin inc(q);queue[q]: =h^.a[ch]; h^.a[ch]^.fail: =h; end; while(p<=q)dobegin forch: ='a'to'z'doif(queue[p]^.a[ch]<>nil)thenbegin inc(q); queue[q]: =queue[p]^.a[ch]; k: =queue[p]^.fail; while(k<>h)and(k^.a[ch]=nil)dok: =k^.fail; ifk^.a[ch]=nilthenqueue[q]^.fail: =h elsequeue[q]^.fail: =k^.a[ch]; if(queue[q]^.fail^.e<>-1)thenbegin k: =queue[q]^.fail; queue[q]^.e: =k^.e; end; end; inc(p); end; end; proceduremain; begin p: =h; print(h); m: =length(st)-1; fori: =1tomdobegin ifp^.a[st[i]]<>nilthenbegin p: =p^.a[st[i]]; end elsebegin while(p<>h)and(p^.a[st[i]]=nil)dop: =p^.fail; if(p^.a[st[i]]<>nil)thenp: =p^.a[st[i]]; end; ifp^.e<>-1theninc(f[p^.e]); end; end; begin assign(input,'pass.in');reset(input); assign(output,'pass.out');rewrite(output); build; readln(st); failure; main; j: =0; fori: =1tondoiff[i]>jthenj: =f[i]; ifj<>0thenwrite(j) elsewrite('Nofind'); close(input); close(output); end. Poj1625 Poj2778 题意和Poj1625基本类似 只不过不是求具体答案而是求答案Mod100000的值了 由于舍去了高精度运算我们可以很容易的写出代码 先由AC自动机构造出DFA再在DFA上进行一遍DP 方程同Pku1625注意求模 题意: 给定m个异常基因片段,在所有长度为N的DNA序列中如‘AAAAA....’,'ATTTTT....','ATCG...','CGTA...',.....中不包含异常序列的DNA个数mod100000(十万)的值,这题题解是AC自动机和矩阵乘法,首先建立AC自动机 programpoj2778; typematrix=array[0..101,0..101]ofint64; constmo=100000; vara: 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]oflongint; off: array[0..101]oflongint; code: array[0..101]ofchar; stack: array[0..110]oflongint; comp: array[0..110]ofboolean; proceduremuti(a,b: matrix;varc: matrix); beginfillchar(c,sizeof(c),0); fori: =0tonodesdo forj: =0tonodesdo begin fork: =0tonodesdo c[i,j]: =(a[i,k]*b[k,j]+c[i,j])modmo; end; end; functionanticode(a: char): longint; begincaseaof 'A': exit (1); 'C': exit (2); 'G': exit(3); 'T': exit(4); elseexit(0); end; end; begin readln(m,n); fillchar(son,sizeof(son),$ff); fori: =1tomdo begin readln(a); leng: =length(a); point: =0; forj: =1tolengdo begin ifson[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; whiletop begin inc(top); x: =stack[top]; fori: =1to4do ifson[x,i]<>-1 then begin inc(tail); stack[tail]: =son[x,i]; ifx=0thencontinue; som: =off[x]; repeat ifson[som,i]<>-1 then begin som: =son[som,i]; break; end; som: =off[som]; untilsom<=0; ifsom=0 then ifson[som,i]<>-1 then som: =son[som,i]; ifcomp[som] thencomp[son[x,i]]: =true; off[son[x,i]]: =som; end; end; top: =0;nodes: =0; whiletop begin inc(top); x: =stack[top]; ifcomp[x]thencontinue; ifx>nodesthennodes: =x; fori: =1to4do ifson[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(notcomp[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(notcomp[son[x,i]]) then inc(g[x,son[x,i]]); end; fori: =0tonodesdo b[i,i]: =1; while(n>0)do begin if(nand1)>0 then muti(b,g,b); n: =n>>1; muti(g,g,g); end; fori: =0tonodesdo ans: =(ans+b[0,i])modmo; writeln(ans); end. 第二种题解: constmaxn=100; maxm=50000; base=100000; vartr: array['A'..'Z']oflongint; n,m,i,j,k,tt,h,t,p,root,ans: longint; s: array[1..maxn,1..4]oflongint; opt: array[0..maxm,1..maxn]oflongint; f,q: array[1..maxn]oflongint; d: array[1..maxn]ofboolean; ch: char; procedureallot(varx: longint); vari: longint; begin inc(tt);x: =tt; d[x]: =false;f[x]: =0; fori: =1to4do s[x][i]: =0; end; begin assign(input,'DNAS.in');reset(input); assign(output,'DNAS2.out');rewrite(output); tr['A']: =1;tr['C']: =2; tr['G']: =3;tr['T']: =4; readln(n,m); tt: =0;allot(root); fori: =1tondo begin p: =root; whilenoteolndo begin read(ch); k: =tr[ch]; ifs[p][k]=0 thenallot(s[p][k]); p: =s[p][k]; end; d[p]: =true; readln; end; h: =1;t: =0; f[root]: =root; fori: =1to4do ifs[root][i]=0 thens[root][i]: =root elsebegin inc(t); q[t]: =s[root][i]; f[q[t]]: =root; end; whileh<=tdo begin fori: =1to4do begin p: =f[q[h]]; while(p<>root)and(s[p][i]=0)do p: =f[p]; ifs[p][i]=0 thenp: =root elsep: =s[p][i]; ifs[q[h]][i]=0 thens[q[h]][i]: =p elsebegin inc(t); q[t]: =s[q[h]][i]; ifd[p]thend[q[t]]: =true; f[q[t]]: =p; end; end; inc(h); end; fillchar(opt,sizeof(opt),0); opt[0][root]: =1; fori: =0tom-1do forj: =1tottdo fork: =1to4do begin n: =s[j][k]; ifnot(d[j])andnot(d[n]) thenbegin t: =i+1; opt[t][n]: =(opt[t][n]+opt[i][j])modbase; end; end; ans: =0; fori: =1tottdo ans: =(ans+opt[m][i])modbase; writeln(ans); close(input);close(output); end. Poj3208: 题意 求所有合法解中排第K的解合法解是一个自然数包含子串"666"首先我们得知道求字典序排第K的问题的通用解法这类问题可以转化为求方案数然后O(kN)递推来解决先考虑最简单的方法由小到大枚举出所有方案然后得到第K个虽然时间复杂度很高但是却是我们O(kN)递推的基础首先可以用DP等方法求出指定前缀时的方案数对于每一个前缀搜索的策略是遍历这个前缀下所有的方案每枚举出一个解就让计数器+1不断的逼近排名K的方案而有了求出的指定前缀的方案数我们就可以大步地累加计数器来逼近排名位为K的方案假设我们已经求出了前i-1位正在求第i位由字典序从小到大枚举第i位每枚举出一位我们就得到了一个长为i的前缀判断计数器加上前缀状况下的方案数是不是大于K大于就表明这一位就是当前枚举出的值否则让计数器加上方案数继续枚举这样复杂度就是O(kN)了k就是每一位可以取的值总数那么这个问题就转化为求
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ac 自动机 有限 状态