poj3691(ac自动机+dp)

来源:互联网 发布:centos 7 ntfs 挂载 编辑:程序博客网 时间:2024/05/21 04:16

链接:点击打开链接

题意:给出一个母串,和n个子串问最少修改几个字母能使母串不含任何一个子串,如果不能输出-1

代码:

#include <queue>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <algorithm>using namespace std;const int INF=0x3f3f3f3f;int dp[1005][1005];int fail[1005];int str[1005][5],dis[1005];int root;char c[5]="ACGT";int change(char C){    if(C=='A')    return 0;    if(C=='C')    return 1;    if(C=='G')    return 2;    return 3;}void insert(char *s){    int u=0;    for(;*s;s++){        if(!str[u][change(*s)])        str[u][change(*s)]=root++;        u=str[u][change(*s)];    }    dis[u]=1;                                   //dis代表u这个节点是否可行}void getfail(){    int u,v,i,temp;    queue<int>q;    q.push(0);    while(q.size()){       u=q.front();q.pop();       for(i=0;i<4;i++){            if(!str[u][i])            str[u][i]=str[fail[u]][i];            else{                temp=str[u][i];                if(u)                fail[temp]=str[fail[u]][i];                dis[temp]|=dis[fail[temp]];     //根据自动机找出所有的不能出现的串的节点                q.push(temp);            }        }    }}int main(){                                     //其实整个思想就是将原串变成一个不含标记    int n,i,j,x,y,z,v,ans,len,cas;              //的字符串,而标记就用tire树+自动机来解决    cas=1;    char s1[1005];    while(scanf("%d",&n)!=EOF&&n){    root=1;    memset(str,0,sizeof(str));    memset(dis,0,sizeof(dis));    memset(fail,0,sizeof(fail));    for(i=0;i<n;i++){        scanf("%s",s1);        insert(s1);    }    scanf("%s",s1);    len=strlen(s1);    getfail();    for(x=0;x<=len;x++)    for(y=0;y<root;y++)    dp[x][y]=INF;    dp[0][0]=0;    for(x=0;x<len;x++)    for(y=0;y<root;y++)    if(dp[x][y]<INF){        for(j=0;j<4;j++){            v=str[y][j];            if(dis[v])                                  continue;               if(s1[x]==c[j])                     //通过每个节点的子节点进行转移            dp[x+1][v]=min(dp[x+1][v],dp[x][y]);            else            dp[x+1][v]=min(dp[x+1][v],dp[x][y]+1);        }    }    ans=INF;    for(j=0;j<root;j++)    ans=min(ans,dp[len][j]);    if(ans==INF)    printf("Case %d: -1\n",cas++);    else    printf("Case %d: %d\n",cas++,ans);    }    return 0;}

0 0
原创粉丝点击