poj3691DNA repair

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int N=1005;
const int INF=0x3ffffff;
int tot=0,dp[N][N];
struct node{
    int son[4],fail;
    bool dan;
}trie[N];
void init(){
    for(int i=0;i<=tot;i++){
       trie[i].fail=trie[i].dan=0;
        for(int j=0;j<4;j++)
            trie[i].son[j]=0;
    }
    tot=0;
}
int get(char c){
    switch(c){
        case 'A': return 0;
        case 'T': return 1;
        case 'C': return 2;
        default: return 3;
    }
}
void Insert(char *s){
    int p = 0;
    for(int i=0,len=strlen(s);i<len;i++){
        int t=get(s[i]);
        if(!trie[p].son[t]){
            trie[p].son[t]=++tot;
        }
        p=trie[p].son[t];
    }
    trie[p].dan=true;
}
void build_ac(){
    queue<int> Q;
    for(int i=0;i<4;i++)
        if(trie[0].son[i])
            Q.push(trie[0].son[i]);
    while(!Q.empty()){
        int u=Q.front();Q.pop();
        for(int i=0;i<4;i++){
            int t=trie[u].son[i];
            int f=trie[u].fail;
            if(t){
                trie[t].fail=trie[f].son[i];
                if(trie[trie[f].son[i]].dan){
                    trie[t].dan=true;
                }
                Q.push(trie[u].son[i]);
            }else trie[u].son[i]=trie[f].son[i];
        }
    }
}
//dp[i][j],表示到达查找串第i个字符时,对应于AC自动机的j节点所需要的最小改变数。\
状态转移为dp[i][j] = min( dp[i][j], dp[i-1][j]+get(s[i-1])!=k))
int Query(char *s){
    for(int i=0,len=strlen(s);i <= len;i++)
        for(int j=0;j <= tot;j++)
        dp[i][j]=INF;
    dp[0][0]=0;//
    for(int i=1,len=strlen(s);i <= len;i++){
        for(int j=0;j <= tot;j++){
            for(int k=0;k<4;k++){
                if(!trie[trie[j].son[k]].dan){
                    dp[i][trie[j].son[k]]=min(dp[i][trie[j].son[k]],dp[i-1][j]+(get(s[i-1])!=k));//dp[i][trie[j].son[k]]
                }
            }
        }
    }
    int ret=INF;
    for(int i=0,len=strlen(s);i <= tot;i++)
        ret=min(ret,dp[len][i]);
    return ret==INF?-1:ret;
}
int n,cas;
char s[N];
int main(){
    while(scanf("%d",&n)==1&&n){
        init();
        while(n--){
            scanf(" %s",s);
            Insert(s);
        }
        build_ac();
        scanf(" %s",s);
        printf("Case %d: %d\n",++cas,Query(s));
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值