poj3691 DNA repair[DP+AC自动机]

$给定 n 个模式串,和一个长度为 m 的原串 s,求至少修改原串中的几个字符可以使得原串中不包含任一个模式串。模式串总长度 ≤ 1000,m ≤ 1000。$


先建出模式串的AC自动机,然后考虑怎么求最优解。考虑AC自动机上DP,设$f_{i,j}$走了$i$步之后在$j$节点时候的最少修改次数。

标记处所有不能走到的点(即走到就匹配了的点,即后缀为某一模式串的所有点),走点的时候应当回避这些点,转移的时候向合法的状态转移,分两种。

一种沿着原串$s_i$走,$f_{i+1,to_j}\leftarrow f_{i,j}$,另一种是走其他路,$f_{i+1,to_j'}\leftarrow f_{i,j}+1$。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<queue>
 7 #define dbg(x) cerr << #x << " = " << x <<endl
 8 using namespace std;
 9 typedef long long ll;
10 typedef double db;
11 typedef pair<int,int> pii;
12 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
13 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
14 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
15 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
16 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
17 template<typename T>inline T read(T&x){
18     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
19     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
20 }
21 const int N=1000+7,INF=0x3f3f3f3f;
22 int ha[128],tr[N][4],ban[N],nxt[N],legal[N],cnt,tot;
23 char s[N];
24 int n;
25 inline void Insert(){
26     int len=strlen(s+1),x=0;
27     for(register int i=1,c=ha[s[1]];i<=len;++i,c=ha[s[i]]){
28         if(!tr[x][c])tr[x][c]=++tot;
29         x=tr[x][c];
30     }
31     ban[x]=1;
32 }
33 queue<int> q;
34 inline void Build(){
35     legal[cnt=1]=0;
36     memset(nxt,0,sizeof nxt);
37     for(register int i=0;i<4;++i)if(tr[0][i])nxt[tr[0][i]]=0,q.push(tr[0][i]);
38     while(!q.empty()){
39         int x=q.front();q.pop();
40         if(ban[nxt[x]])ban[x]=1;
41         if(!ban[x])legal[++cnt]=x;
42         for(register int i=0;i<4;++i)
43             if(tr[x][i])nxt[tr[x][i]]=tr[nxt[x]][i],q.push(tr[x][i]);
44             else tr[x][i]=tr[nxt[x]][i];
45     }
46 }
47 #define j legal[_]
48 int f[N][N],ans,T;
49 inline void dp(){
50     memset(f,0x3f,sizeof f);
51     f[0][0]=0;ans=INF;
52     int len=strlen(s+1);
53     for(register int i=0;i<len;++i)
54         for(register int _=1;_<=cnt;++_)if(f[i][j]<INF){
55             int c=ha[s[i+1]];//dbg(i),dbg(j),dbg(f[i][j]);
56             for(register int k=0;k<4;++k)
57                 if(!ban[tr[j][k]]&&(c^k))
58                     MIN(f[i+1][tr[j][k]],f[i][j]+1);
59             if(!ban[tr[j][c]])MIN(f[i+1][tr[j][c]],f[i][j]);
60         }
61     for(register int _=1;_<=cnt;++_)MIN(ans,f[len][j]);
62 }
63 #undef j
64 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
65     ha['A']=0,ha['C']=1,ha['G']=2,ha['T']=3;
66     while(read(n)){
67         memset(ban,0,sizeof ban);memset(tr,0,sizeof tr),tot=0;
68         for(register int i=1;i<=n;++i)scanf("%s",s+1),Insert();
69         Build();scanf("%s",s+1);dp();
70         printf("Case %d: %d\n",++T,ans<INF?ans:-1);
71     }
72     return 0;
73 }
View Code

总结:AC自动机上DP多为$f_{i,j}$型状态设计,需要考虑每一步各种转移情况。过于浅薄

转载于:https://www.cnblogs.com/saigyouji-yuyuko/p/11558737.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值