题意:容易理解...

思路:首先一开始容易想到要用到dp,开设一个dp[41][41][41][41][501]的数组来解决,但是明显内存已经超出范围了,于是就想如何减少内存呢?只要知道A、T、C、G其中三个的个数,则另一个也能算出,于是空间可以缩小到:41*41*41*500,但是还是不行啊!想了好久还是没找到方法,于是就问了一个大神,他的一个提示给了我灵感:虽然A、T、C、G的个数范围是[0,40],但是numa+numc+numg+numt的范围也是[0,40],于是就可以推出numa*numc*numg*numt的范围为[0,15000](自己写四个for循环可以算出最大为13000多),于是就可以压缩成一个dp[15000][501]的数组了。后来看了网上的方法,他们用了什么变进制,我表示现在还没看懂!!

代码实现:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<queue>
using namespace std;
struct node{
    int next[4];
    int fail;
    int num;
    void init()
    {
        memset(next,0,sizeof(next));
        fail=0;
        num=0;
    }
}a[505];
int tot,n;
int hash[41][41][41][41];
int ta,tc,tg,tt;
int dp[15000][505];
char keyword[15];
char S[45];
int MAX(int a,int b)
{
    return a>b?a:b;
}
void chushihua()
{
    memset(dp,-1,sizeof(dp));
    ta=tc=tg=tt=0;
    tot=0;
    a[0].init();
}
int hash1(char x)
{
       if(x=='A')
        return 0;
    else if(x=='C')
        return 1;
    else if(x=='G')
        return 2;
    else
        return 3;
}
void insert(char *str)//建立字典树
{
    int index,p=0;
    for(;*str!='\0';str++)
    {
        index=hash1(*str);
        if(a[p].next[index]==0)
        {
            a[++tot].init();
            a[p].next[index]=tot;
        }
        p=a[p].next[index];
    }
    a[p].num++;
}
void build_ac()//建立trie图
{
    int i,p,cur,son;
    queue<int>Q;
    Q.push(0);
    while(!Q.empty())
    {
        p=Q.front();
        Q.pop();
        for(i=0;i<4;i++)
        {
            if(a[p].next[i]!=0)
            {
                son=a[p].next[i];
                cur=a[p].fail;
                if(p==0)
                    a[son].fail=0;
                else
                {
                    while(cur&&a[cur].next[i]==0)
                        cur=a[cur].fail;
                    a[son].fail=a[cur].next[i];
                }
                if(a[a[son].fail].num)
                    a[son].num+=a[a[son].fail].num;
                Q.push(son);
            }
            else
                a[p].next[i]=a[a[p].fail].next[i];
        }
    }
}
void yasuo()//进行压缩
{
    int i,j,k,l,num=0;
    for(i=0;S[i]!='\0';i++)
        if(S[i]=='A')
            ta++;
        else if(S[i]=='C')
            tc++;
        else if(S[i]=='G')
            tg++;
        else
            tt++;
    for(i=0;i<=ta;i++)
        for(j=0;j<=tc;j++)
            for(k=0;k<=tg;k++)
                for(l=0;l<=tt;l++)
                    hash[i][j][k][l]=num++;
}
void solve(int zuhao)
{
   int i,j,k,l,p,q,son,x1,x2,max=0;
   dp[0][0]=0;
   for(i=0;i<=ta;i++)
       for(j=0;j<=tc;j++)
           for(k=0;k<=tg;k++)
               for(l=0;l<=tt;l++)
               {
                   if(i+j+k+l==0)
                       continue;
                   x1=hash[i][j][k][l];//解压
                   for(p=0;p<=tot;p++)
                   {
                       for(q=0;q<4;q++)
                       {
                           if(q==0&&i-1>=0)
                               x2=hash[i-1][j][k][l];
                           else if(q==1&&j-1>=0)
                               x2=hash[i][j-1][k][l];
                           else if(q==2&&k-1>=0)
                               x2=hash[i][j][k-1][l];
                           else if(q==3&&l-1>=0)
                               x2=hash[i][j][k][l-1];
                           else
                               continue;
                           if(dp[x2][p]==-1)
                               continue;
                           son=a[p].next[q];
                           dp[x1][son]=MAX(dp[x1][son],dp[x2][p]+a[son].num);
                           if(dp[x1][son]>max)
                               max=dp[x1][son];
                       }
                   }
               }
   printf("Case %d: ",zuhao);
   printf("%d\n",max);
}
int main()
{
    int zuhao=0;
    while(scanf("%d",&n)!=EOF&&n)
    {
        zuhao++;
        chushihua();
        getchar();
        while(n--)
        {
            scanf("%s",keyword);
            insert(keyword);
        }
        build_ac();
        scanf("%s",S);
        yasuo();
        solve(zuhao);
    }
    return 0;
}

hdu 3341(ac自动机+状态压缩)的更多相关文章

  1. HDU 4511 (AC自动机+状态压缩DP)

    题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...

  2. hdu 4057(ac自动机+状态压缩dp)

    题意:容易理解... 分析:题目中给的模式串的个数最多为10个,于是想到用状态压缩dp来做,它的状态范围为1-2^9,所以最大为2^10-1,那我们可以用:dp[i][j][k]表示长度为i,在tri ...

  3. hdu 2825(ac自动机+状态压缩dp)

    题意:容易理解... 分析:在做这道题之前我做了hdu 4057,都是同一种类型的题,因为题中给的模式串的个数最多只能为10个,所以我们就很容易想到用状态压缩来做,但是开始的时候我的代码超时了dp时我 ...

  4. Lost's revenge HDU - 3341 AC自动机+DP(需要学会如何优雅的压缩状态)

    题意: 给你n个子串和一个母串,让你重排母串最多能得到多少个子串出现在重排后的母串中. 首先第一步肯定是获取母串中每个字母出现的次数,只有A T C G四种. 这个很容易想到一个dp状态dp[i][A ...

  5. HDU 4057 Rescue the Rabbit ( AC自动机 + 状态压缩DP )

    模板来自notonlysuccess. 模式串只有10个,并且重复出现的分值不累加,因此很容易想到状态压缩. 将模式串加入AC自动机,最多有10*100个状态. dp[i][j][k]:串长为i,在T ...

  6. Wireless Password - HDU 2825(ac自动机+状态压缩)

    题目大意:有个人想破解他邻居的密码,他邻居告诉了一些关于这个密码的信息,并且给他一个单词集合,他用这些信息判断一下最少有多少种密码. 1->, 所有的密码都是有小写字母组成. 2->,密码 ...

  7. HDU 4758 Walk Through Squares( AC自动机 + 状态压缩DP )

    题意:给你两个串A,B, 问一个串长为M+N且包含A和B且恰好包含M个R的字符串有多少种组合方式,所有字符串中均只含有字符L和R. dp[i][j][k][S]表示串长为i,有j个R,在自动机中的状态 ...

  8. POJ 3691 (AC自动机+状态压缩DP)

    题目链接:  http://poj.org/problem?id=3691 题目大意:给定N个致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题 ...

  9. bzoj1195 神奇的ac自动机+状态压缩dp

    /* 难的不是ac自动机,是状态压缩dp 之前做了一两题类似题目,感觉理解的还不够透彻 */ #include<iostream> #include<cstdio> #incl ...

随机推荐

  1. tornado的cookie和secure cookie

    tornado里面有关几个cookie的处理,在web.py文件里. get_cookie, set_cookie普通的设置cookie, clear_cookie, clear_all_cookie ...

  2. **【ci框架】精通CodeIgniter框架

    http://blog.csdn.net/yanhui_wei/article/details/25803945 一.大纲 1.codeigniter框架的授课内容安排 2.codeigniter框架 ...

  3. POJ1442Black Box

    http://poj.org/problem?id=1442 题意 : 题目中对给出的数字有两种操作ADD(I)操作,将ADD括号里的数字 I 加到数列里边去,然后是自动排好序的,每一个数列前边都会有 ...

  4. HBase入门

    /×××××××××××××××××××××××××××××××××××××××××/ Author:xxx0624 HomePage:http://www.cnblogs.com/xxx0624/ ...

  5. [SQL Server 系] -- 模糊查询

    SQL Server中的通配符有下面四种 通配符 说明 % 包含零个或多个字符的任意字符串 _(下划线) 任意单个字符 [ ] 任意在指定范围或集合中的单个字符 [^ ] 任意不在指定范围或集合中的单 ...

  6. moto xt800 刷机到2.2.2

    老机器啊,原来2.1的系统大多数软件都不能装sbf刷机包+工具+教程下载地址:http://u.115.com/file/bhdlwl2x 刷完之后如果RSD Lite显示刷机结果为失败,不要担心,手 ...

  7. Compare_Connect_Letter

    题目描述: 比较两个数字mn和nm(如果mn<nm则m<n, 如果nm<mn则n<m,否则n=m) 连接这两个数字 如(mnnm) //比较两个数字mn和nm(如果mn< ...

  8. Windows下Subversion和Apache的安装及配置(一)

    1.序 Subversion可谓版本控制软件中的佼佼者,其开源性,易用性已受到众多软件开发者首选的版本控制软件.在这里我想记录我安装Subversion和Apache的过程.注意,Subversion ...

  9. Linux磁盘管理命令

    1.磁盘分割: fdisk [root@linux ~]# fdisk [-l] 装置名称 参数: -l :输出后面接的装置所有的partition内容.若仅有fdisk -l时, 则系统将会把整个系 ...

  10. C语言复习笔记-17种小算法-解决实际问题

    判断日期为一年中的第几天(考虑闰年) 1 /* 2 * 计算该日在本年中是第几天,注意闰年问题 3 * 以3月5日为例,应该先把前两个月的加起来,然后再加上5天即本年的第几天 4 * 特殊情况,闰年且 ...