HDU 3341 状态压缩DP+AC自动机

 题目大意:

调整基因的顺序,希望使得最后得到的基因包含有最多的匹配串基因,使得所能达到的智商最高

这里很明显要用状态压缩当前AC自动机上点使用了基因的情况所能达到的最优状态

我最开始对于状态的保存是,针对基因的个数转化为最小的二进制个数保存,但是浪费了很多二进制位,比如8 -> 1000,那么之后的1001,1010...1111都没用到

就MLE了

然后自己只能在压缩

比如数量为2 , 3 , 4 , 5

那么jz[0] = 1 , jz[1] = 2+1 , jz[2] = 2*1+3*3+1 , jz[3] = 2*1+3*3+4*12+1

那么可以根据这种进制进行解码转码了

那么状态数就能通过解码转码轻松获得了

可能自己写的比较挫吧,跑c++跑不过,g++倒是完全没问题

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <cmath>
  5 #include <queue>
  6 using namespace std;
  7 #define LL long long
  8 #define clr(x) memset(x , 0 , sizeof(x))
  9 #define MAX_SIZE 502
 10 #define CHAR_SIZE 4
 11 const int MAX_STATE = 100000;
 12 int n;
 13 char str[50];
 14 
 15 int Hash(char c){
 16     if(c=='A') return 0;
 17     else if(c == 'C') return 1;
 18     else if(c=='G') return 2;
 19     else return 3;
 20 }
 21 
 22 struct AC_Machine{
 23     int sz , ch[MAX_SIZE][CHAR_SIZE] , fail[MAX_SIZE], val[MAX_SIZE] , gene[MAX_SIZE];
 24     void init(){
 25         sz = 1;
 26         clr(ch[0]) , clr(val);
 27         gene[0] = 0;
 28     }
 29 
 30     void insert(char *s){
 31         int n=strlen(s) , u=0;
 32         for(int i=0 ; i<n ; i++){
 33             int c = Hash(s[i]);
 34             if(!ch[u][c]){
 35                 clr(ch[sz]);
 36                 val[sz] = gene[sz] = 0;
 37                 ch[u][c] = sz++;
 38             }
 39             u = ch[u][c];
 40         }
 41         gene[u] ++;
 42         val[u] = 1;
 43     }
 44 
 45     void get_fail(){
 46         queue<int> Q;
 47         fail[0] = 0;
 48         for(int c=0 ; c<CHAR_SIZE ; c++){
 49             int u = ch[0][c];
 50             if(u) {Q.push(u);fail[u]=0;}
 51         }
 52         while(!Q.empty()){
 53             int r = Q.front();
 54             val[r] |= val[fail[r]];
 55             Q.pop();
 56             for(int c=0 ; c<CHAR_SIZE ; c++){
 57                 int u = ch[r][c];
 58                 if(!u){ch[r][c]=ch[fail[r]][c] ; continue;}
 59                 fail[u] = ch[fail[r]][c];
 60                 Q.push(u);
 61             }
 62         }
 63     }
 64 }ac;
 65 
 66 int dp[MAX_SIZE][MAX_STATE];
 67 int cnt[4] , jz[4];
 68 int code[4] , save[4];
 69 void decode(int state)
 70 {
 71     for(int i=3 ; i>=0 ; i--){
 72         code[i] = state/jz[i];
 73         state -= code[i]*jz[i];
 74     }
 75 }
 76 
 77 int encode(int *code)
 78 {
 79     int ret = 0;
 80     for(int i=3 ; i>=0 ; i--) ret+=code[i]*jz[i];
 81     return ret;
 82 }
 83 
 84 void DP()
 85 {
 86     int all = encode(cnt);
 87     for(int i=0 ; i<=all ; i++)
 88         for(int j=0 ; j<ac.sz ; j++) dp[j][i] = -1;
 89     dp[0][0] = 0;
 90     for(int i=0 ; i<=all ; i++){
 91         for(int j=0 ; j<ac.sz ; j++){
 92             if(dp[j][i]<0) continue;
 93             decode(i);
 94             for(int k=0 ; k<4 ; k++){
 95                 if(code[k]>=cnt[k]) continue;
 96                 int v = ac.ch[j][k];
 97                 int tmp = v , num=0;
 98                 while(tmp&&ac.val[tmp]){
 99                     if(ac.gene[tmp]) num+=ac.gene[tmp];
100                     tmp = ac.fail[tmp];
101                 }
102                 code[k]++;
103                 int newst = encode(code);
104                 code[k]--;
105                 dp[v][newst] = max(dp[j][i]+num , dp[v][newst]);
106             }
107         }
108     }
109 }
110 
111 void solve()
112 {
113     int  len = strlen(str);
114     memset(cnt , 0 , sizeof(cnt));
115     for(int i=0 ; i<len ; i++) cnt[Hash(str[i])]++;
116     jz[0] = 1 , jz[1] = cnt[0]+1 , jz[2] = 1+cnt[0]+cnt[1]*jz[1] , jz[3] = cnt[2]*jz[2]+jz[2];
117     DP();
118 }
119 
120 int main()
121 {
122    // freopen("in.txt" , "r" , stdin);
123     int cas = 0;
124     while(scanf("%d" , &n) , n)
125     {
126         ac.init();
127         for(int i=0 ; i<n ; i++){
128             scanf("%s" , str);
129             ac.insert(str);
130         }
131         ac.get_fail();
132         scanf("%s" , str);
133         solve();
134         int all = encode(cnt);
135         int ret = -1;
136         for(int i=0 ; i<ac.sz ; i++) ret = max(ret , dp[i][all]);
137         printf("Case %d: %d
" , ++cas , ret);
138     }
139     return 0;
140 }
原文地址:https://www.cnblogs.com/CSU3901130321/p/4749829.html