HDU 3341 Lost's revenge AC自动机+ 状态压缩DP

题意:这个题目和HDU2457有点类似,都是AC自动机上的状态dp,题意就是给你只含有'A','T','C','G',四个字符的子串和文本串,问你文本串如何排列才可以使得文本串中包含有更多的模式串

解题思路:我们知道了 有 num[0] 个 'A', num[1] 个 ‘T’, num[2] 个 ‘C’,num[3] 个‘G’, 我们的可以知道暴力的思路就是把所有的文本串都枚举出来然后一一匹配。我们膜拜了一下春哥以后,就可以有以下思路:  把一个串的信息压缩一下,把具有同样个数字符的串看成是同一种情况  比如 AATCG  和 TCGAA 看成是同一种,然后就对不同情况在 AC自动机上的不同状态进行dp,  dp[i][j], i表示  串压缩以后的 值  ,j 表示  i串现在在 AC自动机状态 j 上, dp[i][j] 表示 i 在j 上的最大值。

这里我们压缩有一种巧妙的方法  ,  相当于进位制的压缩。

最后还有一种情况,,模板串可以相同  千万注意.

  1 // File Name: temp.cpp
  2 // Author: darkdream
  3 // Created Time: 2014年09月11日 星期四 15时18分4秒
  4 
  5 #include<vector>
  6 #include<list>
  7 #include<map>
  8 #include<set>
  9 #include<deque>
 10 #include<stack>
 11 #include<bitset>
 12 #include<algorithm>
 13 #include<functional>
 14 #include<numeric>
 15 #include<utility>
 16 #include<sstream>
 17 #include<iostream>
 18 #include<iomanip>
 19 #include<cstdio>
 20 #include<cmath>
 21 #include<cstdlib>
 22 #include<cstring>
 23 #include<ctime>
 24 #include<queue>
 25 #define LL long long
 26 #define maxn 705
 27 
 28 using namespace std;
 29 int dp[15000][505];   
 30 int num[6];
 31 int adv[6]; 
 32 struct Trie
 33 {
 34     int next[maxn][4],fail[maxn],end[maxn];
 35     int root, L;
 36     int newnode()
 37     {
 38         memset(next[L],-1,sizeof(next[L]));
 39         end[L++] = 0 ;
 40         return L-1;
 41     }
 42     void init()
 43     {
 44         L = 0 ; 
 45         root = newnode();
 46     }
 47     void insert(int buf[],int len)
 48     {
 49         int now = root;
 50         for(int i = 0 ;i < len ;i ++)
 51         {
 52             if(next[now][buf[i]] ==  -1)
 53             {
 54                 next[now][buf[i]] = newnode();
 55             }
 56             now = next[now][buf[i]];
 57         }
 58         end[now] ++;
 59     }
 60     void build()
 61     {
 62         queue<int> Q;
 63         fail[root] = root; 
 64         for(int i = 0;i < 4;i ++)
 65         {
 66             if(next[root][i] == -1)
 67             {
 68                 next[root][i] = root;  //指向root 是没有问题的,我们主要是通过end 数组对个数进行计数的。    
 69             }else{
 70                 fail[next[root][i]] = root;
 71                 Q.push(next[root][i]);
 72             }
 73         }
 74         while(!Q.empty())
 75         {
 76             int now = Q.front();
 77             Q.pop();
 78             for(int i = 0 ;i < 4;i ++)
 79             {
 80                 if(next[now][i] == -1)
 81                 {
 82                     next[now][i] =  next[fail[now]][i]; 
 83                 }
 84                 else{
 85                     fail[next[now][i]] = next[fail[now]][i];
 86                     if(end[next[fail[now]][i]] != 0 )
 87                         end[next[now][i]] += end[fail[next[now][i]]];  // 计算 end 最多。 
 88                     Q.push(next[now][i]);
 89                 }
 90             }
 91         }
 92     }
 93     void query( int ca)
 94     {
 95         //end[3] = 1;
 96         memset(dp,-1,sizeof(dp));
 97         dp[0][0] = 0;
 98         int ans = 0 ; 
 99         int mx = num[0]*adv[0] + num[1]*adv[1] + num[2]*adv[2] + num[3]* adv[3];
100         for(int i = 0;i <= mx ;i ++ )
101         {
102            int tnum[5];
103            int k = i ; 
104            for(int j = 0 ;j < 4 ;j ++)
105            {
106              tnum[j] = k / adv[j];
107              k = k %adv[j];
108            }
109            for(int j = 0;j < L;j ++)
110            {
111               if(dp[i][j] != -1)
112               {
113                for(int s = 0 ;s < 4;s ++)
114                {
115                    if(num[s] - tnum[s] > 0 )
116                    {
117                       dp[i+adv[s]][next[j][s]] = max(dp[i+ adv[s]][next[j][s]] ,dp[i][j] +  end[next[j][s]]);  
118                    }
119                }
120               }
121              // printf("%d ",dp[i][j]);
122                
123            }
124            //printf("
");
125         }
126         for(int i = 0 ;i < L ;i ++)
127             ans = max(dp[mx][i],ans);
128         printf("Case %d: %d
",ca,ans);
129     }
130 };
131 char buf[3000];
132 int  temp[3000];
133 Trie ac;
134 void change(int len)
135 {
136     for(int i = 0;i < len;i ++)
137     {
138        if(buf[i] == 'A')
139        {
140          temp[i] = 0 ; 
141        }else if(buf[i] == 'T'){
142          temp[i] = 1; 
143        }else if(buf[i] == 'G')
144        {
145           temp[i] = 2; 
146        }else if(buf[i] == 'C')
147        {
148           temp[i] = 3; 
149        }
150     }
151 }
152 int main(){
153     int n;
154     int ca= 0 ;
155     //freopen("in","r",stdin);
156     while(scanf("%d",&n) != EOF,n)
157     {
158         ca ++ ; 
159         ac.init();
160         int len;
161         memset(num,0,sizeof(num));
162         for(int i =1 ;i <= n;i ++)
163         {
164           scanf("%s",buf);
165           len = strlen(buf);
166           change(len);
167           ac.insert(temp,len);
168         }
169         ac.build();
170         scanf("%s",buf);
171         len = strlen(buf);
172         change(len);
173         memset(num,0,sizeof(num));
174         for(int i = 0 ;i < len;i ++)
175             num[temp[i]] ++ ; 
176         for(int i = 0 ;i < 4;i ++)
177         {
178             adv[i] = 1 ; 
179             for(int j = i+1;j  < 4;j ++)
180             {
181                adv[i] *= (num[j]+1) ;
182             }
183         //    printf("%d ",adv[i]);
184         }
185         //printf("
");
186         ac.query(ca);
187     }
188     return 0;
189 }
View Code
没有梦想,何谈远方
原文地址:https://www.cnblogs.com/zyue/p/3974652.html