hdu 2457 AC自动机DP
题意: 给出了一些病毒串的基因, 又给出了一个基因串,问至少修改多少个基因串中的字符可以不含病毒串。
思路: 这道题是用AC自动机搞的, 好久没写AC自动机了。
这道题的主要思路是构造基因串, 保证构造的基因串不含病毒串, 并且与给出的串相比修改的最少。
1、首先利用病毒串构造自动机, 但是需要注意两点,一是如果fall的结尾标记是病毒串的结尾,那么当前位置也要标记是病毒串的结尾。 如果next为-1, 那么一定要赋一个值,一般赋为fall的next,如果是root的话那就直接是root就行。将每个节点看成是一个状态。
2、进行DP, 对于初始化为INF的DP, 最好加一个continue, DP的过程其实是构造串的过程。
dp[i][j]表示构造到第i个字符的时候在j状态时需要修改的最小值。
x = s[j].next[k]; x必须是可达状态
dp[i+1][x] = min( dp[i+1][x], dp[i][j] + (a[i+1]!=k) );
AC代码:
View Code
1 #include<iostream> 2 #include<queue> 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 const int N = 2010, INF = 1<<29; 7 struct node 8 { 9 int f; 10 int next[4]; 11 int fall; 12 void init() 13 { 14 memset(next,-1,sizeof(next)); 15 fall = -1; 16 f = 0; 17 } 18 } s[N]; 19 int p; 20 char a[N]; 21 22 inline void preprocess() 23 { 24 s[p=0].init(); 25 s[0].fall = -1; 26 } 27 28 int get(char a) 29 { 30 if(a == 'A') return 0; 31 if(a == 'C') return 1; 32 if(a == 'G') return 2; 33 return 3; 34 } 35 36 void insert(char *a) 37 { 38 int ind = 0; 39 int i; 40 for(i=0; a[i]; ++i) 41 { 42 int x=get(a[i]); 43 if(s[ind].next[x]==-1) 44 { 45 s[++p].init(); 46 s[ind].next[x]=p; 47 } 48 ind = s[ind].next[x]; 49 } 50 ++s[ind].f; 51 } 52 53 void build_ac() 54 { 55 int root=0; 56 s[root].fall=-1; 57 queue<int> q; 58 q.push(root); 59 while (!q.empty()) 60 { 61 int t=q.front(); 62 q.pop(); 63 int i; 64 for (i=0; i<4; ++i) 65 { 66 int ind = s[t].next[i]; 67 if(ind != -1) 68 { 69 if (t == root) 70 { 71 s[ind].fall = root; 72 } 73 else 74 { 75 int p = s[t].fall; 76 while (p != -1) 77 { 78 if (s[p].next[i] != -1) 79 { 80 s[ind].fall = s[p].next[i]; 81 int x = s[p].next[i]; 82 if(s[x].f) 83 s[ind].f = 1; 84 break; 85 } 86 p = s[p].fall; 87 } 88 89 if (p == -1) 90 { 91 s[ind].fall = root; 92 } 93 } 94 q.push(ind); 95 } 96 else 97 { 98 if(t == 0) 99 s[t].next[i] = 0; 100 else 101 { 102 int x = s[t].fall; 103 s[t].next[i] = s[x].next[i]; 104 } 105 } 106 } 107 } 108 } 109 110 111 int n, dp[N][N]; 112 113 int DP() 114 { 115 for(int i=0; i<=n; i++) 116 { 117 for(int j=0; j<=p; j++) 118 dp[i][j] = INF; 119 } 120 dp[0][0] = 0; 121 for(int i=0; i<n; i++) 122 { 123 for(int j=0; j<=p; j++) 124 { 125 if(dp[i][j] == INF) continue; 126 for(int k=0; k<4; k++) 127 { 128 int x = s[j].next[k]; 129 if(s[x].f) continue; 130 dp[i+1][x] = min( 131 dp[i+1][x], dp[i][j] + (a[i+1]!=k) ); 132 } 133 } 134 } 135 int ans = INF; 136 for(int i=0; i<=p; i++) 137 ans = min(ans, dp[n][i]); 138 if(ans == INF) return -1; 139 return ans; 140 } 141 142 int main() 143 { 144 int test = 0; 145 while(scanf("%d", &n) != EOF && n) 146 { 147 test++; 148 preprocess(); 149 for(int i=0; i<n; i++) 150 { 151 scanf("%s",a); 152 insert(a); 153 } 154 155 scanf("%s",a+1); 156 n = strlen(a+1); 157 for(int i=1; i<=n; i++) 158 a[i] = get(a[i]); 159 build_ac(); 160 printf("Case %d: %d\n", test, DP()); 161 } 162 return 0; 163 }


浙公网安备 33010602011771号