zoukankan      html  css  js  c++  java
  • POJ 3691 DNA repair(自动机DP)

    题意:先给出m个DNA片段(含致病基因),然后给一个长为n的DNA序列,求最少需要修改多少次,使得这个DNA序列不含致病基因。修改操作定义为将DNA中某个碱基变为另一个碱基,如将A变为G

    数据范围:1<=m<=50,1<=n<=1000

    分析:先建自动机,然后DP。

    状态设计:dp[i][j]为从根结点出发走 i 步后到达状态 j 最少需要修改的次数。

    状态转移:

    1、dp[i][j]=MIN(dp[i-1][k]),从状态k能根据s[i]跳到状态j,无需修改;

    2、dp[i][j]=MIN(dp[i-1][k])+1,从状态k不能根据s[i]跳到状态j,需要修改s[i]。(注意区分DP的状态和自动机的状态)

    初始化:dp[0][0]=0,其余的dp[0][i]=INF.

    View Code
    #include <stdio.h>
    #include <string.h>
    #include <queue>
    using namespace std;
    #define N 51
    #define LEN 21
    #define INF 0x3f3f3f3f
    #define MIN(a,b) ((a)<(b)?(a):(b))
    int next[N*LEN][4];
    int fail[N*LEN];
    bool flag[N*LEN];
    int n,node;
    int dp[1010][N*LEN];
    char s[1010];
    int len;
    void init()
    {
        node=1;
        memset(next[0],0,sizeof(next[0]));
    }
    void add(int cur,int k)
    {
        memset(next[node],0,sizeof(next[node]));
        flag[node]=0;
        next[cur][k]=node++;
    }
    int hash(char c)
    {
        switch(c)
        {
        case 'A':
            return 0;
        case 'C':
            return 1;
        case 'G':
            return 2;
        case 'T':
            return 3;
        }
    }
    void insert(char *s)
    {
        int i,cur,k;
        for(i=cur=0; s[i]; i++)
        {
            k=hash(s[i]);
            if(!next[cur][k])   add(cur,k);
            cur=next[cur][k];
        }
        flag[cur]=1;
    }
    void build_ac()
    {
        queue<int>q;
        int cur,nxt,tmp;
    
        fail[0]=0;
        q.push(0);
    
        while(!q.empty())
        {
            cur=q.front(),q.pop();
            for(int k=0; k<4; k++)
            {
                nxt=next[cur][k];
                if(nxt)
                {
                    if(!cur)    fail[nxt]=0;
                    else
                    {
                        for(tmp=fail[cur]; tmp && !next[tmp][k]; tmp=fail[tmp]);
                        fail[nxt]=next[tmp][k];
                    }
                    if(flag[fail[nxt]]) flag[nxt]=1;
                    q.push(nxt);
                }
                else    next[cur][k]=next[fail[cur]][k];
            }
        }
    }
    void solve()
    {
        memset(dp,0x3f,sizeof(dp));
        dp[0][0]=0;
    
        len=strlen(s+1);
        for(int step=1; step<=len; step++)
        {
            for(int pre=0; pre<node; pre++)
            {
                if(flag[pre])   continue;
                for(int k=0; k<4; k++)
                {
                    int cur=next[pre][k];
                    if(hash(s[step])==k)
                    {
                        dp[step][cur]=MIN(dp[step-1][pre],dp[step][cur]);
                    }
                    else
                    {
                        dp[step][cur]=MIN(dp[step-1][pre]+1,dp[step][cur]);
                    }
                }
            }
        }
        int ans=INF;
        for(int state=0; state<node; state++)
        {
            if(!flag[state])
            {
                ans=MIN(ans,dp[len][state]);
            }
        }
        if(ans<INF) printf("%d\n",ans);
        else    puts("-1");
    }
    int main()
    {
        int kase=0;
        while(scanf("%d",&n),n)
        {
            init();
            for(int i=0; i<n; i++)
            {
                scanf("%s",s);
                insert(s);
            }
            scanf("%s",s+1);
            build_ac();
            printf("Case %d: ",++kase);
            solve();
        }
        return 0;
    }
  • 相关阅读:
    flutter开发环境的搭建
    创建一个android项目
    android studio 安装与配置
    sentinel-dashboard.jar 安装
    三:nacos的配置中心
    二:nacos 的服务注册
    spring boot 在windows下的 批文件部署
    一:nacos 的安装与启动方式
    mysql 命令行安装方式
    Git 出现 Permission denied 时,重新生成ssh密钥
  • 原文地址:https://www.cnblogs.com/algorithms/p/2628834.html
Copyright © 2011-2022 走看看