题目大意:给出n个模式串,和一个母串,问可以改变最少多少个母串中的字符可以使得母串不包含模式串
dp[i][j]表示长度为i,走到j号节点时,最少修改几次
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std ; const int maxn = 1111 ; short dp[maxn][1111] ; int min ( int a , int b ) { return a < b ? a : b ; } class AC_auto { private : int tot ; int c[4][maxn] ; int id[maxn] ; int fail[maxn] ; queue<int> Q ; public : int new_node () { int i ; for ( i = 0 ; i < 4 ; i ++ ) c[i][tot] = 0 ; id[tot] = 0 ; fail[tot] = 0 ; return tot ++ ; } void init () { tot = 0 ; while ( !Q.empty () ) Q.pop () ; new_node () ; } int get_k ( char v ) { int k ; switch ( v ) { case 'A' : k = 0 ; break ; case 'G' : k = 1 ; break ; case 'C' : k = 2 ; break ; case 'T' : k = 3 ; break ; } return k ; } void insert ( char *s ) { int now = 0 ; for ( ; *s ; s ++ ) { int k = get_k ( *s ) ; if ( !c[k][now] ) c[k][now] = new_node () ; now = c[k][now] ; } id[now] = 1 ; } void get_fail () { int u = 0 , i , j , e ; for ( i = 0 ; i < 4 ; i ++ ) if ( c[i][u] ) Q.push ( c[i][u] ) ; while ( !Q.empty () ) { u = Q.front () ; Q.pop () ; for ( i = 0 ; i < 4 ; i ++ ) { if ( !c[i][u] ) { c[i][u] = c[i][fail[u]] ; continue ; } j = fail[u] , e = c[i][u] ; fail[e] = c[i][j] ; id[e] |= id[fail[e]] ; Q.push ( e ) ; } } } void work ( char *s ) { int i , j , l ; int n = strlen ( s + 1 ) ; for ( i = 0 ; i <= n ; i ++ ) for ( j = 0 ; j < tot ; j ++ ) dp[i][j] = -1 ; dp[0][0] = 0 ; for ( i = 0 ; i < n ; i ++ ) for ( j = 0 ; j < tot ; j ++ ) { if ( dp[i][j] == -1 ) continue ; int k = get_k ( s[i+1] ) ; for ( l = 0 ; l < 4 ; l ++ ) { int add = 0 ; if ( l != k ) add = 1 ; int e = c[l][j] ; if ( !id[e] ) { if ( dp[i+1][e] == -1 ) dp[i+1][e] = dp[i][j] + add ; else dp[i+1][e] = min ( dp[i+1][e] , dp[i][j] + add ) ; } } } int ans = -1 ; for ( i = 0 ; i < tot ; i ++ ) { if ( dp[n][i] == -1 ) continue ; if ( ans == -1 ) ans = dp[n][i] ; else ans = min ( ans , dp[n][i] ) ; } printf ( "%d\n" , ans ) ; } } ac ; char s[maxn] ; int main () { int n , i ; int cas = 0 ; while ( scanf ( "%d" , &n ) != EOF ) { if ( n == 0 ) break ; cas ++ ; ac.init () ; for ( i = 1 ; i <= n ; i ++ ) { scanf ( "%s" , s ) ; ac.insert ( s ) ; } ac.get_fail () ; scanf ( "%s" , s + 1 ) ; printf ( "Case %d: " , cas ) ; ac.work ( s ) ; } }