POJ 3691 TRIE图+DP

题意:

已知一个DNA串和一些病毒DNA序列,求出最少改变DNA串中多少个字符,能使得串中不包含任意一个病毒序列。

 

题解:

嗯,和上一个trie图一样,把病毒建成trie,只要母串不能再trie上走到危险节点即可(危险节点就是病毒dna序列的终止的那个被标有fg的节点)。

然后trie图上的dp,要走到危险节点的时候,枚举转移即可。

 

 

View Code
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 
 7 #define M 1111
 8 #define N 111
 9 #define INF 0x3f3f3f3f
10 
11 using namespace std;
12 
13 struct TR
14 {
15     int son[4]; int f; bool fg;
16 }tr[N*N];
17 
18 int map[N],cnt,q[N*N],n,m,cas;
19 char str[N],a[M];
20 int dp[M][N*N];
21 
22 inline void insert(char *s)
23 {
24     int len=strlen(s+1);
25     int now=1;
26     for(int i=1;i<=len;i++)
27     {
28         if(!tr[now].son[map[s[i]]]) tr[now].son[map[s[i]]]=++cnt;
29         now=tr[now].son[map[s[i]]];
30     }
31     tr[now].fg=true;
32 }
33 
34 inline void build()
35 {
36     int h=1,t=2,sta,now,tmp;
37     q[1]=1;
38     while(h<t)
39     {
40         sta=q[h++];
41         for(int i=0;i<4;i++)
42         {
43             now=tr[sta].son[i];
44             if(sta==1) tmp=1;
45             else tmp=tr[tr[sta].f].son[i];
46             if(now==0) tr[sta].son[i]=tmp;
47             else
48             {
49                 tr[now].f=tmp; tr[now].fg|=tr[tmp].fg;
50                 q[t++]=now;
51             }
52         }
53     }
54 }
55 
56 inline void read()
57 {
58     memset(tr,0,sizeof tr);
59     tr[cnt=1].f=1;
60     for(int i=1;i<=n;i++)
61     {
62         scanf("%s",str+1);
63         insert(str);
64     }
65     scanf("%s",a+1);
66     m=strlen(a+1);
67     build();
68 }
69 
70 inline void go()
71 {
72     memset(dp,0x3f,sizeof dp);
73     dp[0][1]=0;
74     for(int i=0;i<m;i++)
75         for(int j=1;j<=cnt;j++)
76         {
77             for(int k=0;k<4;k++)
78                 if(!tr[tr[j].son[k]].fg) dp[i+1][tr[j].son[k]]=min(dp[i+1][tr[j].son[k]],dp[i][j]+1);
79             if(!tr[tr[j].son[map[a[i+1]]]].fg) dp[i+1][tr[j].son[map[a[i+1]]]]=min(dp[i+1][tr[j].son[map[a[i+1]]]],dp[i][j]);
80         }
81     int ans=INF;
82     for(int i=1;i<=cnt;i++) ans=min(ans,dp[m][i]);
83     if(ans==INF) ans=-1;
84     printf("Case %d: %d\n",++cas,ans);
85 }
86 
87 int main()
88 {
89     map['A']=0; map['G']=1; map['C']=2; map['T']=3;
90     while(scanf("%d",&n),n) read(),go();
91     return 0;
92 }

 

 

posted @ 2013-03-05 21:24  proverbs  阅读(427)  评论(0编辑  收藏  举报