题目大意:
就是现在有n( 1 <= n <= 50 )个DNA序列是有疾病的,现在有一个DNA序列(长度不超过1000),要求替换掉其中的字符(只能替换成A,C,G,T)使得该DNA序列不再包含疾病序列,问最少要替换掉多少个字符,如果不存在这样的解,输出-1
大致思路:
就是一个简单的AC自动机+动态规划,没有什么难点。。。
状态转移方程说明见代码。
Result : Accepted Memory : 4328 KB Time : 62 ms
/*
* Author: Gatevin
* Created Time: 2014/11/22 15:00:55
* File Name: Kagome.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
int n;
const int inf = 9999999;
int dp[1010][1010];
/*
* dp[i][j]表示长度为i在Trie树的节点j结尾的串最少需要替换多少个字母才能不包含疾病序列
* 那么不难发现 当dp[i][j]存在时
* dp[i + 1][next[j][t]] = min(dp[i + 1][next[j][t]], dp[i][j]) (M[s[i]] == t) M[s[i]]为字符s[i]的编号
* dp[i + 1][next[j][t]] = min(dp[i + 1][next[j][t]], dp[i][j] + 1) (M[s[i]] != t)
*/
map <char, int> M;
char s[1010];
struct Trie
{
int next[1010][4], fail[1010];
bool end[1010];
int L, root;
int newnode()
{
for(int i = 0; i < 4; i++)
next[L][i] = -1;
end[L++] = 0;
return L - 1;
}
void init()
{
L = 0;
root = newnode();
return;
}
void insert(char *s)
{
int now = root;
for(; *s; s++)
{
if(next[now][M[*s]] == -1)
next[now][M[*s]] = newnode();
now = next[now][M[*s]];
}
end[now] = 1;
return;
}
void build()
{
queue <int> Q;
fail[root] = root;
Q.push(root);
while(!Q.empty())
{
int now = Q.front();
Q.pop();
if(end[fail[now]]) end[now] = 1;
for(int i = 0; i < 4; i++)
if(next[now][i] == -1)
next[now][i] = now == root ? root : next[fail[now]][i];
else
{
fail[next[now][i]] = now == root ? root : next[fail[now]][i];
Q.push(next[now][i]);
}
}
return;
}
void solve(int cas)
{
int len = strlen(s);
for(int i = 0; i <= len; i++)
for(int j = 0; j < L; j++)
dp[i][j] = inf;
dp[0][0] = 0;
for(int i = 0; i < len; i++)
for(int j = 0; j < L; j++)
{
if(dp[i][j] == inf) continue;
for(int k = 0; k < 4; k++)
{
if(!end[next[j][k]])//只有当没走到疾病节点的时候更新状态
{
if(k == M[s[i]])//是否更换当前字母
dp[i + 1][next[j][k]] = min(dp[i + 1][next[j][k]], dp[i][j]);
else
dp[i + 1][next[j][k]] = min(dp[i + 1][next[j][k]], dp[i][j] + 1);
}
}
}
int ans = inf;
for(int i = 0; i < L; i++)
ans = min(ans, dp[len][i]);
printf("Case %d: %d\n", cas, ans == inf ? -1 : ans);
return;
}
};
Trie AC;
int main()
{
char ts[22];
int cas = 0;
M['A'] = 0; M['C'] = 1; M['G'] = 2; M['T'] = 3;
while(scanf("%d", &n), n)
{
cas++;
AC.init();
while(n--)
{
scanf("%s", ts);
AC.insert(ts);
}
scanf("%s", s);
AC.build();
AC.solve(cas);
}
return 0;
}