题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2457
题目大意:给你一些Bug字符组,再给你一个长字符串,问要使长字符串中不出现这些BUG字符组,需要至少改动几个字符
思路:这道题AC自动机部分我会,直接模板敲上去记录一下端点就完事了,然后dp部分我又实在是不会,好烦~~
这里说一些其他大佬的dp思路:用DP[i][j]表示长度为i (i <= 1000),状态为j(j <= 50*20 + 1)的字符串变成目标串S需要改变的最少字符,设初始状态j = 0,那么DP[0][0] = 0,其他均为无穷大。从长度i到i+1进行状态转移,每次转移枚举共四个字符(A、C、G、T),如果枚举到的字符和S对应位置相同则改变值T=1,否则T=0;那么有状态转移方程 DP[i][j] = Min{ DP[i-1][ fromstate ] + T, fromstate为所有能够到达j的状态 };最后DP[n][j]中的最小值就是答案
贴一下AC代码吧:
#include <bits/stdc++.h>
using namespace std;
const int INF = 0X3f3f3f3f;
char str[1005];
struct Trie
{
int next[1005][4], fail[1005];
bool last[1005];
int root, L;
int newnode()
{
for(int i = 0; i < 4; ++i)
next[L][i] = -1;
last[L++] = false;
return L-1;
}
void init()
{
L = 0;
root = newnode();
}
int getch(char ch)
{
if(ch == 'A') return 0;
else if(ch == 'G') return 1;
else if(ch == 'C') return 2;
else if(ch == 'T') return 3;
}
void insert(char str[])
{
int len = strlen(str), now = root;
for(int i = 0; i < len; ++i){
if(next[now][getch(str[i])] == -1)
next[now][getch(str[i])] = newnode();
now = next[now][getch(str[i])];
}
last[now] = true;
}
void build()
{
queue<int> q;
fail[root] = root;
for(int i = 0; i < 4; ++i){
if(next[root][i] == -1)
next[root][i] = root;
else{
fail[next[root][i]] = root;
q.push(next[root][i]);
}
}
while(!q.empty()){
int now = q.front();
q.pop();
if(last[fail[now]]) last[now] = true;
for(int i = 0; i < 4; ++i){
if(next[now][i] == -1)
next[now][i] = next[fail[now]][i];
else{
fail[next[now][i]] = next[fail[now]][i];
q.push(next[now][i]);
}
}
}
}
int dp[1005][1005];
int solve(char str[])
{
int len = strlen(str);
for(int i = 0; i <= len; ++i){
for(int j = 0; j < L; ++j)
dp[i][j] = INF;
}
dp[0][root] = 0;
for(int i = 0; i < len; ++i){
for(int j = 0; j < L; j++){
if(dp[i][j] < INF){
for(int k = 0; k < 4; ++k){
int news = next[j][k];
if(last[news]) continue;
int tmp;
if(k == getch(str[i])) tmp = dp[i][j];
else tmp = dp[i][j]+1;
dp[i+1][news] = min(dp[i+1][news], tmp);
}
}
}
}
int ans = INF;
for(int j = 0; j < L; j++)
ans = min(ans, dp[len][j]);
if(ans == INF) ans = -1;
return ans;
}
}trie;
int main()
{
int n, cas = 0;
while(~scanf("%d", &n)){
if(n == 0) break;
cas++;
trie.init();
while(n--){
scanf("%s", str);
trie.insert(str);
}
trie.build();
scanf("%s", str);
printf("Case %d: %d\n", cas, trie.solve(str));
}
return 0;
}