第一次。。自己分析出来的dp。。。。。
和之前做过的题很像,感觉有关构造字符串的题都有套路。
dp中一定包含一维trie图中的节点状态(好像是废话)
这道题我们用dp[i][j]表示长度为i节点状态为j最少消去的数量。
状态转移就是dp[i][u] = min(dp[i][u], dp[i-1][j]+(ch!=ss[i]));
#include<bits/stdc++.h>
using namespace std;
int T = 0;
int Hash(char ch) {
if(ch == 'A') return 0;
else if(ch == 'T') return 1;
else if(ch == 'G') return 2;
else if(ch == 'C') return 3;
else return -1;
}
struct AC{
int nex[1005][4], root, tot;
int f[1005], ed[1005];
int newnode() {
for(int i = 0; i < 4; i++) nex[tot][i] = -1;
ed[tot] = 0;
return tot++;
}
void init() {
tot = 0;
root = newnode();
}
void insert(char *s) {
int u = root, len = strlen(s);
for(int i = 0; i < len; i++) {
int ch = Hash(s[i]);
if(nex[u][ch] == -1) nex[u][ch] = newnode();
u = nex[u][ch];
}
ed[u] = 1;
}
void getfail() {
queue<int>Q;
for(int i = 0; i < 4; i++) {
if(nex[root][i] == -1) nex[root][i] = root;
else {
f[nex[root][i]] = root;
Q.push(nex[root][i]);
}
}
while(!Q.empty()) {
int u = Q.front();Q.pop();
ed[u] |= ed[f[u]];
for(int i = 0; i < 4; i++) {
if(nex[u][i] == -1) nex[u][i] = nex[f[u]][i];
else {
f[nex[u][i]] = nex[f[u]][i];
Q.push(nex[u][i]);
}
}
}
}
}ac;
char ss[1005];
int dp[1005][1005];
int main() {
int n;
while(scanf("%d", &n) == 1 && n) {
ac.init();
for(int i = 0; i < n; i++) {
scanf("%s", ss);
ac.insert(ss);
}
ac.getfail();
scanf("%s", ss);
int len = strlen(ss);
memset(dp, 0x3f3f3f3f, sizeof(dp));
dp[0][0] = 0;
for(int i = 1; i <= len; i++) {
int ch = Hash(ss[i-1]);
for(int s = 0; s < ac.tot; s++) {
if(ac.ed[s] || dp[i-1][s] == 0x3f3f3f3f) continue;
for(int c = 0; c < 4; c++) {
int u = ac.nex[s][c];
if(ac.ed[u]) continue;
if(ch == c) {
dp[i][u] = min(dp[i][u], dp[i-1][s]);
}
else dp[i][u] = min(dp[i][u], dp[i-1][s]+1);
}
}
}
int res = 0x3f3f3f3f;
for(int s = 0; s < ac.tot; s++)
res = min(res, dp[len][s]);
printf("Case %d: %d\n", ++T, (res==0x3f3f3f3f)?-1:res);
}
}