hdu3341 AC自动机

       这题没意思,卡时间卡的太紧了,主要就是知道这种类型的状态压缩怎么写就好了。

       假设ACGT的总数分别为num[0],num[1],num[2],num[3],那么对于ACGT的数量分别为ABCD的状态可以记录为:
                     A*(num[1]+1)*(num[2]+1)*(num[3]+1) + B*(num[2]+1)*(num[3]+1)+ C*(num[3]+1) +D。

      

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define N 505
#define Max 4
using namespace std;
int num[N],next[N][4],fail[N];
int cnt,root;
int newnode()
{
    fail[cnt] = 0;
    num[cnt] = 0;
    return cnt++;
}
int hash(char s)
{
    if(s == 'A')return 0;
    if(s == 'C')return 1;
    if(s == 'G')return 2;
    if(s == 'T')return 3;
}
void insert(char *str)
{
    int i=0,s;
    int t = root;
    while(str[i])
    {
        s = hash(str[i]);
        if(next[t][s]==0)
            next[t][s]=newnode();
        t = next[t][s];
        i++;
    }
    num[t]++;
}
void build_ac_automation()
{
    queue<int>q;
    int tmp = root;
    q.push(tmp);
    while(!q.empty())
    {
        tmp=q.front();
        q.pop();
        for(int i=0; i<Max; i++)
            if(next[tmp][i]==NULL)
            {
                if(tmp==root)next[tmp][i] = root;
                else next[tmp][i] = next[fail[tmp]][i];
            }
            else
            {
                if(tmp==root)fail[next[tmp][i]] = root;
                else
                {
                    fail[next[tmp][i]] = next[fail[tmp]][i];
                    num[next[tmp][i]]+=num[next[fail[tmp]][i]];
                }
                q.push(next[tmp][i]);
            }
    }
}
char s[50];
int dp[505][11*11*11*11+5];
int sum[4],bit[4];
int main()
{
    int n,i,j,cas = 1;
    while(scanf("%d",&n)&&n)
    {
        cnt = 0;
        root = newnode();
        memset(sum,0,sizeof(sum));
        memset(dp,-1,sizeof(dp));
        memset(next,0,sizeof(next));
        for(i = 1;i<=n;i++)
        {
            scanf("%s",s);
            insert(s);
        }
        build_ac_automation();
        scanf("%s",s);
        int l = strlen(s);
        for(i = 0;i<l;i++)
            sum[hash(s[i])]++;
        bit[0] = (sum[1]+1)*(sum[2]+1)*(sum[3]+1);
        bit[1] = (sum[2]+1)*(sum[3]+1);
        bit[2] = (sum[3]+1);
        bit[3] = 1;
        memset(dp,-1,sizeof(dp));
        dp[root][0] = 0;
        for(int A = 0;A <= sum[0];A++)
            for(int B = 0;B <= sum[1];B++)
                for(int C = 0;C <= sum[2];C++)
                    for(int D = 0;D <= sum[3];D++)
                    {
                        int st = A*bit[0] + B*bit[1] + C*bit[2] + D*bit[3];
                        for(int i = 0;i < cnt;i++)
                            if(dp[i][st] >= 0)
                            {
                                for(int k = 0;k < 4;k++)
                                {
                                    if(k == 0 && A == sum[0])continue;
                                    if(k == 1 && B == sum[1])continue;
                                    if(k == 2 && C == sum[2])continue;
                                    if(k == 3 && D == sum[3])continue;
                                    dp[next[i][k]][st+bit[k]] = max(dp[next[i][k]][st+bit[k]],dp[i][st]+num[next[i][k]]);
                                }
                            }
                    }
        int ans = 0;
        int status = sum[0]*bit[0] + sum[1]*bit[1] + sum[2]*bit[2] + sum[3]*bit[3];
        for(int i = 0;i < cnt;i++)
            ans = max(ans,dp[i][status]);
        printf("Case %d: %d\n",cas++,ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值