zoukankan      html  css  js  c++  java
  • 【hdu3341-Lost's revenge】DP压缩+AC自动机

    题意:给定只含有A、G、C、T的n个模板串,一个文本串,文本串任意两个字母可互换位置,问最多能匹配多少个模板串。
    注意:匹配同一个模板串匹配了两次,ans+=2;(可重复)

    题解:

    原本想到一个简单dp : 开一个数组d[t1][t2][t3][t4][x],t1~t4分别表示4个字母各有多少个,x表示当前位置。

    然后这个数组为40*40*40*40*600,各种爆空间。

    后来才知道要用压缩。。。

    比如ACGT分别有5,6,7,8个。那t1为6进制,可以放0~5,t2为7进制……

    然后类比10进制,把它压成一个10进制的数,这个数最大是11*11*11*11=14641.

    压缩的原理:

    我打了两个程序,dp一个用了递归,一个用了for循环,递归那个一直超时,for那个就A了。递归跟for循环差别这么大吗?

      1 //DP为for循环递推形式 AC
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<iostream>
      6 #include<queue>
      7 using namespace std;
      8 
      9 const int N=600;
     10 struct node{
     11     int sum,fail,son[5];
     12 }a[N];
     13 queue<int> q;
     14 char s[N];
     15 int n,num,t[5],sum[5],k[5],d[15000][N];
     16 bool vis[15000][N];
     17 int maxx(int x,int y){return x>y ? x:y;}
     18 int minn(int x,int y){return x<y ? x:y;}
     19 
     20 int idx(char c)
     21 {
     22     if(c=='A') return 1;
     23     if(c=='G') return 2;
     24     if(c=='C') return 3;
     25     if(c=='T') return 4;
     26 }
     27 
     28 void clear(int x)
     29 {
     30     a[x].fail=a[x].sum=0;
     31     memset(a[x].son,0,sizeof(a[x].son));
     32 }
     33 
     34 void trie(char *c)
     35 {
     36     int x=0,l=strlen(c);
     37     for(int i=0;i<l;i++)
     38     {
     39         int ind=idx(c[i]);
     40         if(!a[x].son[ind])
     41         {
     42             num++;
     43             clear(num);
     44             a[x].son[ind]=num;
     45         }
     46         x=a[x].son[ind];
     47     }
     48     a[x].sum++;
     49 }
     50 
     51 void buildAC()
     52 {
     53     while(!q.empty()) q.pop();
     54     for(int i=1;i<=4;i++) 
     55         if(a[0].son[i]) q.push(a[0].son[i]);
     56     while(!q.empty())
     57     {
     58         int x=q.front();q.pop();
     59         int fail=a[x].fail;
     60         for(int i=1;i<=4;i++)
     61         {
     62             if(a[x].son[i])
     63             {
     64                 int y=a[x].son[i],z=a[fail].son[i];
     65                 a[y].fail=z;
     66                 a[y].sum+=a[z].sum;
     67                 q.push(a[x].son[i]);
     68             }
     69             else a[x].son[i]=a[fail].son[i];
     70         }
     71     }
     72 }
     73 
     74 int makeup()
     75 {
     76     return t[1]*k[1]+t[2]*k[2]+t[3]*k[3]+t[4]*k[4];
     77 }
     78 
     79 int dp()
     80 {
     81     memset(d,-1,sizeof(d));
     82     d[0][0]=0;
     83     int ans=0,ss=sum[1]+sum[2]+sum[3]+sum[4];
     84     for(int l=0;l<=ss;l++)//当前选择了多少个点
     85         for(int i=0;i<=num;i++)//当前走到了第i个点
     86             for(t[1]=maxx(0,l-sum[2]-sum[3]-sum[4]);t[1]<=minn(l,sum[1]);t[1]++)//限制 最少选多少 最多选多少
     87                 for(t[2]=maxx(0,l-t[1]-sum[3]-sum[4]);t[2]<=minn(l,sum[2]);t[2]++)
     88                     for(t[3]=maxx(0,l-t[1]-t[2]-sum[4]);t[3]<=minn(l,sum[3]);t[3]++)
     89                     {
     90                         t[4]=l-t[1]-t[2]-t[3];
     91                         int now=makeup();
     92                         if(d[now][i]==-1) continue;
     93                         ans=maxx(ans,d[now][i]);
     94                         for(int j=1;j<=4;j++)
     95                         {
     96                             int y=a[i].son[j];
     97                             if(t[j]+1<=sum[j])
     98                             {
     99                                 t[j]++;
    100                                 int next=makeup();
    101                                 d[next][y]=maxx(d[next][y],d[now][i]+a[y].sum);
    102                                 t[j]--;
    103                             }    
    104                         }
    105                     }
    106     return ans;
    107 }
    108 
    109 int main()
    110 {
    111     freopen("a.in","r",stdin);
    112     freopen("a.out","w",stdout);
    113     int T=0;
    114     while(1)
    115     {
    116         scanf("%d",&n);
    117         if(!n) return 0;
    118         num=0;
    119         clear(0);
    120         for(int i=1;i<=n;i++)
    121         {
    122             scanf("%s",s);
    123             trie(s);
    124         }
    125         buildAC();
    126         scanf("%s",s);
    127         int mx=0,l=strlen(s);
    128         memset(sum,0,sizeof(sum));
    129         memset(vis,0,sizeof(vis));
    130         for(int i=0;i<l;i++) sum[idx(s[i])]++;
    131         for(int i=1;i<=4;i++)
    132         {
    133             k[i]=1;
    134             for(int j=i+1;j<=4;j++)
    135                 k[i]*=(sum[j]+1);
    136             mx+=k[i]*sum[i];
    137         }
    138         printf("Case %d: %d
    ",++T,dp());
    139     }
    140     return 0;
    141 }
      1 //DP为递归形式 TLE
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<iostream>
      6 #include<queue>
      7 using namespace std;
      8 
      9 const int N=600;
     10 struct node{
     11     int sum,fail,son[5];
     12 }a[N];
     13 queue<int> q;
     14 char s[N];
     15 int n,num,t[5],sum[5],k[5],d[15000][N];
     16 bool vis[15000][N];
     17 int maxx(int x,int y){return x>y ? x:y;}
     18 int minn(int x,int y){return x<y ? x:y;}
     19 
     20 int idx(char c)
     21 {
     22     if(c=='A') return 1;
     23     if(c=='G') return 2;
     24     if(c=='C') return 3;
     25     if(c=='T') return 4;
     26 }
     27 
     28 void clear(int x)
     29 {
     30     a[x].fail=a[x].sum=0;
     31     memset(a[x].son,0,sizeof(a[x].son));
     32 }
     33 
     34 void trie(char *c)
     35 {
     36     int x=0,l=strlen(c);
     37     for(int i=0;i<l;i++)
     38     {
     39         int ind=idx(c[i]);
     40         if(!a[x].son[ind])
     41         {
     42             num++;
     43             clear(num);
     44             a[x].son[ind]=num;
     45         }
     46         x=a[x].son[ind];
     47     }
     48     a[x].sum++;
     49 }
     50 
     51 void buildAC()
     52 {
     53     while(!q.empty()) q.pop();
     54     for(int i=1;i<=4;i++) 
     55         if(a[0].son[i]) q.push(a[0].son[i]);
     56     while(!q.empty())
     57     {
     58         int x=q.front();q.pop();
     59         int fail=a[x].fail;
     60         for(int i=1;i<=4;i++)
     61         {
     62             if(a[x].son[i])
     63             {
     64                 int y=a[x].son[i],z=a[fail].son[i];
     65                 a[y].fail=z;
     66                 a[y].sum+=a[z].sum;
     67                 q.push(a[x].son[i]);
     68             }
     69             else a[x].son[i]=a[fail].son[i];
     70         }
     71     }
     72 }
     73 
     74 int makeup(int t1,int t2,int t3,int t4)
     75 {
     76     return t1*k[1]+t2*k[2]+t3*k[3]+t4*k[4];
     77 }
     78 
     79 int dp(int now,int x)
     80 {
     81     int ans=0,t1,t2,t3,t4;
     82     if(vis[now][x]) return d[now][x];
     83     t4=now%k[3];
     84     t3=((now%k[2])-(t4*k[4]))/k[3];
     85     t2=((now%k[1])-(t4*k[4]+t3*k[3]))/k[2];
     86     t1=(now-(t4*k[4]+t3*k[3]+t2*k[2]))/k[1];
     87     for(int i=1;i<=4;i++)
     88     {
     89         int y=a[x].son[i];
     90         if(!y && x) ans=maxx(ans,dp(now,0));                                
     91         else if(i==1 && t1>=1) ans=maxx(ans,a[y].sum+dp(makeup(t1-1,t2,t3,t4),y));
     92         else if(i==2 && t2>=1) ans=maxx(ans,a[y].sum+dp(makeup(t1,t2-1,t3,t4),y));
     93         else if(i==3 && t3>=1) ans=maxx(ans,a[y].sum+dp(makeup(t1,t2,t3-1,t4),y));
     94         else if(i==4 && t4>=1) ans=maxx(ans,a[y].sum+dp(makeup(t1,t2,t3,t4-1),y));
     95     }
     96     d[now][x]=maxx(d[now][x],ans);
     97     vis[now][x]=1;
     98     return d[now][x];
     99 }
    100 
    101 int main()
    102 {
    103     freopen("a.in","r",stdin);
    104     freopen("a.out","w",stdout);
    105     int T=0;
    106     while(1)
    107     {
    108         scanf("%d",&n);
    109         if(!n) return 0;
    110         num=0;
    111         clear(0);
    112         for(int i=1;i<=n;i++)
    113         {
    114             scanf("%s",s);
    115             trie(s);
    116         }
    117         buildAC();
    118         scanf("%s",s);
    119         int mx=0,l=strlen(s);
    120         memset(sum,0,sizeof(sum));
    121         memset(vis,0,sizeof(vis));
    122         for(int i=0;i<l;i++) sum[idx(s[i])]++;
    123         for(int i=1;i<=4;i++)
    124         {
    125             k[i]=1;
    126             for(int j=i+1;j<=4;j++)
    127                 k[i]*=(sum[j]+1);
    128             mx+=k[i]*sum[i];
    129         }
    130         // printf("%d
    ",dp());
    131         memset(d,0,sizeof(d));
    132         printf("Case %d: %d
    ",++T,dp(mx,0));
    133     }
    134     return 0;
    135 }
  • 相关阅读:
    MFC中文件的查找、创建、打开、读写等
    使用DOS比较两个txt文件的差异
    HDU
    LIS(两种方法求最长上升子序列)
    7-17 奥运排行榜 (25 分)
    区间DP
    HDU-1864&&HDU-2602(01背包问题)
    HDU-5968异或密码
    Maximum Value(unique函数,lower_bound()函数,upper_bound()函数的使用)
    博弈结论记录
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5667099.html
Copyright © 2011-2022 走看看