题意:给出一个n个模式串,一个目标串,问把目标串重新排位最多能产生多少个模式串,可以重叠且所有串只包含A C G T。
题解:先统计目标串里A C G T的个数,题目意思转化为用num[0]个A,num[1]个C,num[2]个G,num[3]个T组成的串最多包含多少个模式串。可以先建好trie图,根据trie图然后dp,重点在状态的转移,f[i][s],表示i节点状态是s的最优解,状态可以用hash值表示,hash[i][j][k][l]表示当前有i个A,j个C,k个G,l个T的情况下的状态值,四层循环给每种情况一个值。状态转移方程如果当前字母是a,f[next[i][0]][hash[a][b][c][d]] = max(f[next[i][0]][a][b][c][d], f[i][hash[a - 1][b][c][d] + val[next[i][0]])。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
const int N = 505;
int Next[N][4], val[N], fail[N], sz, n;
int num[4], Hash[41][41][41][41], f[N][15000];
char str[N];
map <char, int> mp;
void init() {
memset(Next[0], 0, sizeof(Next[0]));
val[0] = 0;
sz = 1;
}
void insert(char *s) {
int u = 0, len = strlen(s);
for (int i = 0; i < len; i++) {
int k = mp[s[i]];
if (!Next[u][k]) {
memset(Next[sz], 0, sizeof(Next[sz]));
val[sz] = 0;
Next[u][k] = sz++;
}
u = Next[u][k];
}
val[u]++;
}
void getFail() {
queue<int> Q;
fail[0] = 0;
for (int i = 0; i < 4; i++)
if (Next[0][i]) {
fail[Next[0][i]] = 0;
Q.push(Next[0][i]);
}
while (!Q.empty()) {
int u = Q.front();
Q.pop();
val[u] += val[fail[u]];
for (int i = 0; i < 4; i++) {
if (!Next[u][i])
Next[u][i] = Next[fail[u]][i];
else {
fail[Next[u][i]] = Next[fail[u]][i];
Q.push(Next[u][i]);
}
}
}
}
int main() {
mp['A'] = 0;
mp['C'] = 1;
mp['G'] = 2;
mp['T'] = 3;
int cas = 1;
while (scanf("%d", &n) == 1 && n) {
init();
memset(num, 0, sizeof(num));
memset(f, -1, sizeof(f));
for (int i = 0; i < n; i++) {
scanf("%s", str);
insert(str);
}
getFail();
scanf("%s", str);
int len = strlen(str);
for (int i = 0; i < len; i++)
num[mp[str[i]]]++;
int cnt = 0;
for (int i = 0; i <= num[0]; i++)
for (int j = 0; j <= num[1]; j++)
for (int k = 0; k <= num[2]; k++)
for (int l = 0; l <= num[3]; l++)
Hash[i][j][k][l] = cnt++;
f[0][0] = 0;
int res = 0;
for (int a = 0; a <= num[0]; a++)
for (int c = 0; c <= num[1]; c++)
for (int g = 0; g <= num[2]; g++)
for (int t = 0; t <= num[3]; t++) {
int h1 = Hash[a][c][g][t];
if (a + c + g + t == 0)
continue;
for (int i = 0; i < sz; i++)
for (int j = 0; j < 4; j++) {
int h2;
if (j == 0 && a >= 1)
h2 = Hash[a - 1][c][g][t];
else if (j == 1 && c >= 1)
h2 = Hash[a][c - 1][g][t];
else if (j == 2 && g >= 1)
h2 = Hash[a][c][g - 1][t];
else if (j == 3 && t >= 1)
h2 = Hash[a][c][g][t - 1];
else
continue;
if (f[i][h2] == -1)
continue;
f[Next[i][j]][h1] = max(f[Next[i][j]][h1], f[i][h2] + val[Next[i][j]]);
res = max(res, f[Next[i][j]][h1]);
}
}
printf("Case %d: %d\n", cas++, res);
}
return 0;
}