hdu 3341 Lost's revenge

hdu 3341 Lost's revenge

题意:给出n个子串,和一个母串。问用母串中的字符最多可以组合出几个子串。可以重叠
最裸的是用dp[i][a][b][c][d]表示走到i号节点,用了a个'A' b个'G' c个'C' d个'T',但是这样开不下,用状态压缩,把a,b,c,d压缩成一维,因为总数只有40个,所以压缩后,状态不会很大,开个15555就可以过了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std ;

const int maxn = 555 ;
int dp[maxn][22222] ;
int len , cnt[4] , g[4] ;
const int inf = 11111111 ;

int T ;

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 init ()
{
    T = 1 ;
    int i , j , k , l ;
    for ( i = 0 ; i < 4 ; i ++ )
    {
        T *= ( cnt[i] + 1 ) ;
    }
    g[0] = 1 ;
    for ( i = 1 ; i < 4 ; i ++ ) g[i] = g[i-1] * ( cnt[i-1] + 1 ) ;
}

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 ;
        id[tot] = 0 ;
        fail[tot] = 0 ;
        for ( i = 0 ; i < 4 ; i ++ ) c[i][tot] = 0 ;
        return tot ++ ;
    }

    void init () { while ( !q.empty () ) q.pop () ; tot = 0 ; new_node () ; }

    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] ++ ;
    }

    void get_fail ()
    {
        int i , j , u = 0 ;
        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 ;
                }
                int e = c[i][u] ;
                j = fail[u] ;
                fail[e] = c[i][j] ;
                id[e] += id[fail[e]] ;
                q.push ( e ) ;
            }
        }
    }

    void work ()
    {
        int i , j , k , l , t , f ;
        for ( i = 0 ; i <= tot ; i ++ )
            for ( j = 0 ; j <= T ; j ++ )
                dp[i][j] = -inf ;
        dp[0][0] = 0 ;
        for ( i = 0 ; i < T ; i ++ )
        {
            for ( t = 0 ; t < tot ; t ++ )
            {
                if ( dp[t][i] == -inf ) continue ;
                int u = i ;
                for ( f = 0 ; f < 4 ; f ++ )
                {
                    int p = u % ( cnt[f] + 1 ) ;
                    u = u / ( cnt[f] + 1 ) ;
                    if ( p == cnt[f] ) continue ;
                    int e = i + g[f] ;
                    int v = c[f][t] ;
                    dp[v][e] = max ( dp[v][e] , dp[t][i] + id[v] ) ;
                }
            }
        }
        int ans = 0 ;
        for ( i = 0 ; i < tot ; i ++ )
            ans = max ( ans , dp[i][T-1] ) ;
        printf ( "%d\n" , ans ) ;
    }
} ac ;

char s[55] ;
int main ()
{
    int n , i , j ;
    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 () ;
        for ( i = 0 ; i < 4 ; i ++ ) cnt[i] = 0 ;
        scanf ( "%s" , s ) ;
        len = strlen ( s ) ;
        for ( i = 0 ; i < len ; i ++ )
        {
            int k = get_k ( s[i] ) ;
            cnt[k] ++ ;
        }
        init () ;
        printf ( "Case %d: " , cas ) ;
        ac.work () ;
    }
}
/*
5
AATCATTGCT
TATC
TCCAG
CT
TATCCATGG
TTAAAGAAAT
0
2
ATCCGG
CCGTCAGGG
GATGGAATGTGAACTGACTAGTTTGTTTCCCCC
3
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值