HDOJ 4057 - Rescue the Rabbit 简单的AC自动机+状态压缩DP

                 题意:

                         众所周知..DNA序列由"A","G","T","C"组成....

                         现在N个DNA序列(每个长度没说..假设都小于1000吧...1<=N<=10)...并且告诉每个DNA序列能得到的分数Wi,(|Wi|<=100)...

                         若一个DNA串包含其中的某些串..那么得分就是包括的串分数之和(一个串不管出现了多少次..只算一次)..

                         问..若构造长度为M(1<=M<=100)的DNA序列...能得到的最大分数为多少...

                 题解:

                          裸AC自动机...然后10个DNA子串...状态压缩DP...复杂度有些高 100*1000*1024*4...好久没写AC自动机了..差点写跪....再一个写程序的时候memset最好直接用for循环去代替吧..常数比较大....


Program:

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<queue>
#include<algorithm>
#include<string.h>
#define MAXN 10002
using namespace std;
struct node
{
      int son[4],fail,w;
}P[MAXN];
char s[1005];
bool dp[2][1015][1<<10];
int val[1<<10],turn[30],num;
void initial(int h)
{
      int x;
      for (x=0;x<4;x++) P[h].son[x]=0;
      P[h].fail=P[h].w=0;
}
void Built_Trie(int n)
{
      int h,k,t,x,i,y,len;
      initial(0),num=0;
      for (t=0;t<n;t++)
      {
              scanf("%s%d",s+1,&val[t]),len=strlen(s+1);
              if (len>100) { val[t]=0; continue; }
              h=0;
              for (i=1;i<=len;i++)
              {
                      x=turn[s[i]-'A'];
                      if (!P[h].son[x]) P[h].son[x]=++num,initial(num);
                      h=P[h].son[x];
              }
              P[h].w|=1<<t;
      }
}
void Built_AC()
{
      int h,k,x;
      queue<int> Q;
      while (Q.size()) Q.pop();
      for (x=0;x<4;x++)
         if (P[0].son[x])
           Q.push(P[0].son[x]);
      while (Q.size())
      {
             h=Q.front(),Q.pop();
             for (x=0;x<4;x++)
             {
                     k=P[h].fail;
                     while (k && !P[k].son[x]) k=P[k].fail;
                     P[P[h].son[x]].fail=P[k].son[x];
                     if (!P[h].son[x])
                          P[h].son[x]=P[k].son[x];
                     else
                     {
                          Q.push(P[h].son[x]);
                          k=P[h].fail;
                          while (1)
                          { 
                                P[P[h].son[x]].w|=P[P[k].son[x]].w,k=P[k].fail;
                                if (!k) break;
                          }
                     }
             }
      }
}
int AC_DP(int n,int L)
{
      int l,w,h,x,h1,w1,temp,ans=-1,g=0;
      memset(dp,false,sizeof(dp));
      dp[g][0][0]=true;
      for (l=1;l<=L;l++)
      {
              g=1-g;
              for (h=0;h<=num;h++)
                 for (w=0;w<(1<<n);w++)
                    dp[g][h][w]=false;
              for (h=0;h<=num;h++)
                 for (w=0;w<(1<<n);w++)
                    if (dp[1-g][h][w])
                       for (x=0;x<4;x++)
                       {
                              h1=P[h].son[x];
                              w1=w|P[h1].w;
                              dp[g][h1][w1]=true;
                       }
      }
      for (h=0;h<=num;h++)
        for (w=0;w<(1<<n);w++)
          if (dp[g][h][w])
              dp[g][0][w]=true;
      for (w=0;w<(1<<n);w++)
          if (dp[g][0][w])
          {
                  temp=0;
                  for (x=0;x<n;x++)
                     if (w & 1<<x)
                        temp+=val[x]; 
                  ans=max(ans,temp);
          }
      return ans;
}
int main()
{
      int n,l,ans; 
      turn['A'-'A']=0,turn['G'-'A']=1,
      turn['T'-'A']=2,turn['C'-'A']=3;
      while (~scanf("%d%d",&n,&l))
      {
               Built_Trie(n);
               Built_AC();
               ans=AC_DP(n,l);
               if (ans<0) puts("No Rabbit after 2012!");
                     else printf("%d\n",ans);
      }
      return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值