POJ_3691
这个题目可以直接在生成的trie图的“安全部分”进行dp,用f[i][j]表示第i步走到第j个节点时,最少repair了几个基因。
具体的建立trie图的思想可以参考《Trie图的构建、活用与改进》这篇文章。
#include<stdio.h>
#include<string.h>
#define MAXD 1010
#define INF 0x3f3f3f3f
char gene[MAXD], b[30];
int f[MAXD][MAXD], next[MAXD][4], flag[MAXD], N, e, P[MAXD], q[MAXD];
void add(int cur, int k)
{
++ e;
flag[e] = 0;
memset(next[e], 0, sizeof(next[e]));
next[cur][k] = e;
}
void init()
{
int i, j, k, cur;
e = 0;
flag[e] = 0;
memset(next[e], 0, sizeof(next[e]));
for(i = 0; i < N; i ++)
{
scanf("%s", b);
cur = 0;
for(j = 0; b[j]; j ++)
{
switch(b[j])
{
case 'A' : {k = 0; break;}
case 'T' : {k = 1; break;}
case 'C' : {k = 2; break;}
case 'G' : {k = 3; break;}
}
if(!next[cur][k])
add(cur, k);
cur = next[cur][k];
}
flag[cur] = 1;
}
for(i = 0; i < 4; i ++)
if(!next[0][i])
add(0, i);
scanf("%s", gene);
}
void solve()
{
int i, j, k, u, v, front, rear, ans;
front = rear = P[0] = 0;
q[rear ++] = 0;
while(front < rear)
{
u = q[front ++];
for(i = 0; i < 4; i ++)
{
j = next[u][i];
if(j != 0)
{
q[rear ++] = j;
if(u == 0)
P[j] = 0;
else
{
for(k = P[u]; k != 0; k = P[k])
if(next[k][i])
break;
P[j] = next[k][i];
if(flag[P[j]])
flag[j] = 1;
}
}
else
{
for(k = P[u]; k != 0; k = P[k])
if(next[k][i])
break;
next[u][i] = next[k][i];
}
}
}
memset(f, 0x3f, sizeof(f));
f[0][0] = 0;
for(i = 0; gene[i]; i ++)
{
switch(gene[i])
{
case 'A' : {k = 0; break;}
case 'T' : {k = 1; break;}
case 'C' : {k = 2; break;}
case 'G' : {k = 3; break;}
}
for(u = 0; u <= e; u ++)
if(f[i][u] != INF)
{
for(j = 0; j < 4; j ++)
{
v = next[u][j];
if(!flag[v])
{
if(j == k)
{
if(f[i][u] < f[i + 1][v])
f[i + 1][v] = f[i][u];
}
else
{
if(f[i][u] + 1 < f[i + 1][v])
f[i + 1][v] = f[i][u] + 1;
}
}
}
}
}
ans = INF;
for(j = 0; j <= e; j ++)
if(f[i][j] < ans)
ans = f[i][j];
printf("%d\n", ans == INF ? -1 : ans);
}
int main()
{
int t = 0;
for(;;)
{
scanf("%d", &N);
if(!N)
break;
printf("Case %d: ", ++ t);
init();
solve();
}
return 0;
}