poj3691(ac自动机+dp)

Description
Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a DNA is represented as a string containing characters ‘A’, ‘G’ , ‘C’ and ‘T’. The repairing techniques are simply to change some characters to eliminate all segments causing diseases. For example, we can repair a DNA “AAGCAG” to “AGGCAC” to eliminate the initial causing disease segments “AAG”, “AGC” and “CAG” by changing two characters. Note that the repaired DNA can still contain only characters ‘A’, ‘G’, ‘C’ and ‘T’.
You are to help the biologists to repair a DNA by changing least number of characters.

题意:
最少改变主串多少个字符使得他不包括任何模式串
tip:
dp[i][j]表示主串走了i个字母,当前在自动机的j节点,
然后枚举j的4个可能孩子k。。。注意是强行在第j节点,如果s[i] != ch[j][k] 很明显答案+1 相当于把s[i]强行改成ch[j]k。。。
dp[i+1][v] = min(dp[I][j])

这个v不单单是孩子,还可能是fail的孩子。注意细节

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
int n,m,node;
const int INF = (1<<30);
const int maxn = 1005;
char ss[55][25],s[maxn];
int val[maxn],last[maxn],ch[maxn][5],fail[maxn];

int getpos(char a){
    if(a == 'A')    return 0;
    if(a == 'T')    return 1;
    if(a == 'C')    return 2;
    if(a == 'G')    return 3;
}

void Insert(int v){
    int len = strlen(ss[v]);
    int tmp = 0;
    for(int i = 0; i < len ; i++){
        int pos = getpos(ss[v][i]);
        if(ch[tmp][pos] == 0){
            memset(ch[node],0,sizeof(ch[node]));
            val[node] = 0;
            ch[tmp][pos] = node++;
        }
        tmp = ch[tmp][pos];
    }
    val[tmp] = v;
}

void getfail(){
    queue<int> q;
    int u = 0;
    for(int i = 0; i < 4; i++){
        if(ch[u][i]){
            int tmp = ch[u][i];
            fail[tmp] = 0;
            q.push(tmp);
            last[tmp] = 0;
        }
    }

    while(!q.empty()){
        int tmp = q.front();
        q.pop();
        for(int i = 0; i < 4; i++){
            if(ch[tmp][i]){
                int v = fail[tmp];
                while(v && ch[v][i]==0) v = fail[v];
                fail[ch[tmp][i]] = ch[v][i];
                q.push(ch[tmp][i]);
                last[ch[tmp][i]] = val[fail[ch[tmp][i]]]?fail[ch[tmp][i]] : last[fail[ch[tmp][i]]];
            }
        }
    }
}

void init(){
    node = 1;
    memset(ch[0],0,sizeof(ch[0]));
    memset(last,0,sizeof(last));
    for(int i = 1; i <= m ; i++){
        scanf("%s",ss[i]);
        Insert(i);
    }

}
int dp[maxn][maxn];
void sov(){
    scanf("%s",s);
    int len = strlen(s);
    for(int i = 0 ; i <= len ; i++)
        for(int j =  0 ; j <= node; j++)
            dp[i][j] = INF;
    dp[0][0] = 0;

    for(int i = 0 ; i < len; i++){
        for(int j = 0 ; j < node; j++){
            if(dp[i][j] == INF) continue;
            for(int k = 0 ; k < 4; k++){
                int v;
                if(ch[j][k])    v = ch[j][k];
                else{
                    v = fail[j];
                    while(v &&ch[v][k] == 0) v = fail[v];
                    v = ch[v][k];
                }
                if(last[v]||val[v]) continue;

                if(getpos(s[i]) == k)
                    dp[i+1][v] = min(dp[i+1][v],dp[i][j]);
                else
                    dp[i+1][v] = min(dp[i+1][v],dp[i][j]+1);
              }
        }
    }
    int ans = INF;
    for(int i = 0 ; i < node; i++){
       // printf("dp[%d] = %d\n",i,dp[len][i]);
        ans = min(ans,dp[len][i]);
    }
    if(ans == INF)  printf("-1\n");
    else printf("%d\n",ans);
}


int main(){
    int ca = 1;
    while(~scanf("%d",&m)&&m){
        init();
        //cout <<ch[0][1]<<endl;

        printf("Case %d: ",ca++);
        getfail();
//        for(int i =  0 ; i < node ; i++)
//            printf("last[%d] = %d\n",i,last[i]);
        sov();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值