hdu2457(最少替换多少个字符使主串不包含模式串)ac自动机+dp

题:http://acm.hdu.edu.cn/showproblem.php?pid=2457

题意:给定n个模式串,给定一个主串,问最替换掉多少个字符使主串不包含模式串或输出“-1”表示没有可行的方案;

分析:给n个模式串建立ac自动机,考虑dp[i][j],表示长度为 i , j 节点变换为主串前 i 个的最小操作数,j节点要转换必须使当前节点为“安全点”,即end[trie[i][j]]==0;

   dp转化就只要不是自己就要在转移过程中+1,i 位置取min 给下一位i+1

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int M=2e3+3;
const int maxn=4;
const int inf=0x3f3f3f3f;
int dp[M][M];
char s[M];
struct ac{
    int trie[M][maxn],fail[M];
    bool end[M];
    int tot,root;
    int newnode(){
        for(int i=0;i<maxn;i++)
            trie[tot][i]=-1;
        end[tot++]=0;
        return tot-1;
    }
    void init(){
        memset(end,false,sizeof(end));
        tot=0;
        root=newnode();
    }
    int getid(char c){
        if(c=='A')
            return 0;
        if(c=='G')
            return 1;
        if(c=='T')
            return 2;
        if(c=='C')
            return 3;
    }
    void insert(char buf[]){
        int now=root,len=strlen(buf);
        for(int i=0;i<len;i++){
            int id=getid(buf[i]);
            if(trie[now][id]==-1)
                trie[now][id]=newnode();
            now=trie[now][id];
        }
        end[now]=true;
    }
    void getfail(){
        queue<int>que;
        while(!que.empty())
            que.pop();
        fail[root]=root;
        for(int i=0;i<maxn;i++){
            if(trie[root][i]==-1)
                trie[root][i]=root;
            else{
                fail[trie[root][i]]=root;
                que.push(trie[root][i]);
            }
        }
        while(!que.empty()){
            int now=que.front();
            que.pop();
            if(end[fail[now]])
                end[now]=true;
            for(int i=0;i<maxn;i++){
                if(trie[now][i]!=-1){
                    fail[trie[now][i]]=trie[fail[now]][i];
                    que.push(trie[now][i]);
                }
                else
                    trie[now][i]=trie[fail[now]][i];
            }
        }
    }
}AC;
int main(){
    int n,t=0;
    while(~scanf("%d",&n)&&n){
        AC.init();
        for(int i=0;i<n;i++){
            scanf("%s",s);
            AC.insert(s);
        }
        AC.getfail();
        
            
        scanf("%s",s);
        int len=strlen(s);
        for(int i=0;i<=len;i++)
            for(int j=0;j<AC.tot;j++)
                dp[i][j]=inf;
        dp[0][AC.root]=0;
        for(int i=0;i<len;i++)
            for(int j=0;j<AC.tot;j++)
                if(dp[i][j]<inf){
                    for(int k=0;k<maxn;k++){
                        int now=AC.trie[j][k];
                        if(AC.end[now])
                            continue;
                    //    cout<<now<<"!!"<<endl;
                        int id=AC.getid(s[i]);
                        int add=0;
                        if(id!=k)
                            add++;
                        dp[i+1][now]=min(dp[i+1][now],dp[i][j]+add);
                    //    cout<<dp[i+1][now];
                    }
                }
        int ans=inf;
        for(int i=0;i<AC.tot;i++){
            ans=min(ans,dp[len][i]);
            
        }
            
        printf("Case %d: ",++t);
        if(ans==inf)
            puts("-1");
        else
            printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2020-02-27 14:09  starve_to_death  阅读(185)  评论(0编辑  收藏  举报