zoukankan      html  css  js  c++  java
  • hdu 4057--Rescue the Rabbit(AC自动机+状压DP)

    题目链接

    Problem Description
    Dr. X is a biologist, who likes rabbits very much and can do everything for them. 2012 is coming, and Dr. X wants to take some rabbits to Noah's Ark, or there are no rabbits any more.

    A rabbit's genes can be expressed as a string whose length is l (1 ≤ l ≤ 100) containing only 'A', 'G', 'T', 'C'. There is no doubt that Dr. X had a in-depth research on the rabbits' genes. He found that if a rabbit gene contained a particular gene segment, we could consider it as a good rabbit, or sometimes a bad rabbit. And we use a value W to measure this index.

    We can make a example, if a rabbit has gene segment "ATG", its W would plus 4; and if has gene segment "TGC", its W plus -3. So if a rabbit's gene string is "ATGC", its W is 1 due to ATGC contains both "ATG"(+4) and "TGC"(-3). And if another rabbit's gene string is "ATGATG", its W is 4 due to one gene segment can be calculate only once.

    Because there are enough rabbits on Earth before 2012, so we can assume we can get any genes with different structure. Now Dr. X want to find a rabbit whose gene has highest W value. There are so many different genes with length l, and Dr. X is not good at programming, can you help him to figure out the W value of the best rabbit.
     
    Input
    There are multiple test cases. For each case the first line is two integers n (1 ≤ n ≤ 10),l (1 ≤ l ≤ 100), indicating the number of the particular gene segment and the length of rabbits' genes.

    The next n lines each line contains a string DNAi and an integer wi (|wi| ≤ 100), indicating this gene segment and the value it can contribute to a rabbit's W.
     
    Output
    For each test case, output an integer indicating the W value of the best rabbit. If we found this value is negative, you should output "No Rabbit after 2012!".
     
    Sample Input
    2 4
    ATG 4
    TGC -3
    1 6
    TGC 4
    4 1
    A -1
    T -2
    G -3
    C -4
     
    Sample Output
    4
    4
    No Rabbit after 2012!
     
    Hint
    case 1:we can find a rabbit whose gene string is ATGG(4), or ATGA(4) etc.
    case 2:we can find a rabbit whose gene string is TGCTGC(4), or TGCCCC(4) etc.
    case 3:any gene string whose length is 1 has a negative W.
     
    题意:现在有n个基因片段(用包含A、G、T、C的字符串表示),每个基因片段有一个权值,现在求长为L的基因的最大权值(每个基因片段重复出现算一次,不用计算多次)?
     
    思路:AC自动机+状态压缩DP,dp[i][j][s]表示长为 i 的基因且在AC自动机 tire树上匹配到节点 j 时包含基因片段集合为 s 时合法(即dp[i][j][s]=1,如果等于0 则表示不存在这样的基因),那么由长为 i 的字符串可以递推到长为 i+1 的字符串基因, x=node[j].son[k]->id 和  f=node[j].son[k]->flag => dp[i+1][x][s|f]=1  (0<=k<=3), 最后计算长为L的基因最大权值和,根据dp[L][j][s] 遍历所有节点的所有状态,计算每个状态下的权值和,得到最大权值和。
     
    注意:dp每次根据前一长度下的状态 推 下一长度下的状态,那么可以使用滚动数组减小存储空间。
     
    代码如下:
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <string>
    using namespace std;
    const int N=1005;
    int a[20],tot;
    struct Node
    {
        Node *fail;
        Node *son[4];
        int flag;
        int id;
    }node[N],*root;
    queue<Node*>Q;
    bool dp[2][N][1050];
    
    int f(char c)
    {
        if(c=='A') return 0;
        if(c=='G') return 1;
        if(c=='T') return 2;
        if(c=='C') return 3;
    }
    void insert(string s,int id)
    {
        Node *now=root;
        for(int i=0;i<s.length();i++)
        {
            int x=f(s[i]);
            if(now->son[x]==NULL) now->son[x]=&node[tot++];
            now=now->son[x];
        }
        now->flag|=(1<<(id-1));
    }
    void build()
    {
        Q.push(root);
        while(!Q.empty())
        {
            Node *now=Q.front(); Q.pop();
            for(int i=0;i<4;i++)
            {
                if(now->son[i])
                {
                    Node *p=now->fail;
                    while(p&&(!(p->son[i]))) p=p->fail;
                    now->son[i]->fail=(p)?(p->son[i]):root;
                    now->son[i]->flag|=now->son[i]->fail->flag;
                    Q.push(now->son[i]);
                }
                else now->son[i]=(now!=root)?now->fail->son[i]:root;
            }
        }
    }
    void init()
    {
        tot=1;
        root=&node[0];
        memset(dp,0,sizeof(dp));
        while(!Q.empty()) Q.pop();
        for(int i=0;i<N;i++)
        {
            node[i].fail=NULL;
            node[i].flag=0;
            node[i].id=i;
            for(int j=0;j<4;j++) node[i].son[j]=NULL;
        }
    }
    int main()
    {
        int n,l;
        while(scanf("%d%d",&n,&l)!=EOF)
        {
            init();
            for(int i=1;i<=n;i++)
            {
                string s; cin>>s;
                insert(s,i);
                scanf("%d",&a[i]);
            }
            build();
            dp[0][0][0]=1;
            int cn=0;
            for(int i=0;i<l;i++)
            {
                cn^=1;
                memset(dp[cn],0,sizeof(dp[cn]));
                for(int j=0;j<tot;j++)
                {
                    for(int s=0;s<(1<<n);s++)
                    {
                        if(!dp[cn^1][j][s]) continue;
                        for(int k=0;k<4;k++)
                        {
                            int x=node[j].son[k]->id;
                            int f=node[j].son[k]->flag;
                            dp[cn][x][s|f]=1;
                        }
                    }
                }
            }
            int ans=-99999999;
            for(int i=0;i<tot;i++)
            {
                for(int s=0;s<(1<<n);s++)
                {
                    if(!dp[cn][i][s]) continue;
                    int tmp=0;
                    int x=s;
                    for(int k=1;k<=n;k++)
                    {
                        if(x&1) tmp+=a[k];
                        x>>=1;
                    }
                    ans=max(ans,tmp);
                }
            }
            if(ans<0) puts("No Rabbit after 2012!");
            else printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Android开发利用shareSDK等第三方分享,弹出的是英文名称。例如Genymotion模拟器
    Android开发之viewpager导报错误解决方法:错误代码 Caused by: java.lang.ClassNotFoundException: Didn't find class
    Android开发之数据存储——SharedPreferences基础知识详解,饿补学会基本知识,开发者必会它的用法。
    Android开发工具资料Android Manifest 权限描述大全 随时随地查询权限描述。
    Android,java,php开发最基本的知识,mysql sqlite数据库的增删改查代理,sql语句
    EditText设置输入的类型,只能输入纯数字,只能输入手机号码,只能输入邮箱等等。
    Android开发之强大的网络判断工具,判断是否联网,判断是wifi还是3g网络等java工具代码类
    Android开发之将图片文件转化为字节数组字符串,并对其进行Base64编码处理
    Android开发之华为手机无法看log日志解决方法(亲测可用华为荣耀6)
    Android-PullToRefresh上拉下拉刷新加载更多,以及gridview刷新功能的Library下载地址
  • 原文地址:https://www.cnblogs.com/chen9510/p/7661618.html
Copyright © 2011-2022 走看看