hdu_2457_DNA repair(AC自动机+DP)
题目连接:hdu_2457_DNA repair
题意:
给你N个字符串,最后再给你一个要匹配的串,问你最少修改多少次,使得这个串不出现之前给的N的字符串
题解:
刚学AC自动机,切这题还真不知道怎么来DP,然后看了一下题解,需要在失败指针那里做文章,这里我们要将trie的每一个节点当作一个状态,然后设dp[i][j]表示考虑到第i个字符,j这个trie节点时的最小修改次数,为什么要这样考虑,因为AC自动机在匹配失败的时候会转向其他的节点,所以这里我们要考虑每一个节点的状态,然后当前节点的子节点如果不存在也要处理一下,就指向这个节点的fail指针,这样我们在后面dp的时候才能保证匹配失败的时候回到fail节点
1 #include<cstdio> 2 #include<cstring> 3 #define F(i,a,b) for(int i=a;i<=b;i++) 4 5 inline void up(int &x,int y){if(x>y)x=y;} 6 const int AC_N=1011,inf=1e8; 7 struct AC_automation{ 8 int tr[AC_N][4],cnt[AC_N],Q[AC_N],fail[AC_N],tot; 9 int gt(char x){ 10 if(x=='A')return 0; 11 if(x=='G')return 1; 12 if(x=='C')return 2; 13 if(x=='T')return 3; 14 } 15 void nw(){cnt[++tot]=0;memset(tr[tot],-1,sizeof(tr[tot]));} 16 void init(){tot=-1,fail[0]=-1,nw();} 17 void insert(char *s,int x=0){ 18 for(int len=strlen(s),i=0,w;i<len;x=tr[x][w],i++) 19 if(tr[x][w=gt(s[i])]==-1)nw(),tr[x][w]=tot; 20 cnt[x]=1;//串尾标记 21 } 22 void build(int head=1,int tail=0){ 23 for(Q[++tail]=0;head<=tail;){ 24 for(int i=0,x=Q[head++],p=-1;i<=3;i++)if(~tr[x][i]){ 25 if(x==0)fail[tr[0][i]]=0; 26 else{ 27 for(p=fail[x],fail[tr[x][i]]=0;~p;p=fail[p]) 28 if(~tr[p][i]){fail[tr[x][i]]=tr[p][i];break;} 29 }//如果他失败指针指向的节点的子节点为危险DNA那么这点的子节点也不能取 30 if(cnt[fail[tr[x][i]]])cnt[tr[x][i]]=1; 31 Q[++tail]=tr[x][i]; 32 }else if(x==0)tr[0][i]=0;//不存在的节点指向失败指针的位置 33 else tr[x][i]=tr[fail[x]][i]; 34 } 35 } 36 int dp[1010][1010]; 37 int ask(char *s){ 38 int len=strlen(s),ans=inf; 39 F(i,0,len)F(j,0,tot)dp[i][j]=inf; 40 dp[0][0]=0; 41 F(i,1,len)F(j,0,tot){ 42 if(cnt[j]||dp[i-1][j]==inf)continue; 43 F(k,0,3){ 44 int nxt=tr[j][k]; 45 if(cnt[nxt])continue; 46 up(dp[i][nxt],dp[i-1][j]+(gt(s[i-1])!=k)); 47 } 48 } 49 F(i,0,tot)up(ans,dp[len][i]); 50 return ans==inf?-1:ans; 51 } 52 }AC; 53 54 char buf[1010]; 55 int main(){ 56 int n,ic=1; 57 while(~scanf("%d",&n),n){ 58 AC.init(); 59 F(i,1,n)scanf("%s",buf),AC.insert(buf); 60 AC.build(); 61 scanf("%s",buf); 62 printf("Case %d: %d\n",ic++,AC.ask(buf)); 63 } 64 return 0; 65 }