HDU 4057 Rescue the Rabbit(AC自动机+状态压缩dp)

Rescue theRabbit

Time Limit: 20000/10000 MS(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2365    Accepted Submission(s): 704

Problem Description

Dr. X is abiologist, who likes rabbits very much and can do everything for them. 2012 iscoming, and Dr. X wants to take some rabbits to Noah's Ark, or there are norabbits 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-depthresearch on the rabbits' genes. He found that if a rabbit gene contained aparticular gene segment, we could consider it as a good rabbit, or sometimes abad rabbit. And we use a value W to measure this index.
We can make a example, if a rabbit has gene segment "ATG", its Wwould plus 4; and if has gene segment "TGC", its W plus -3. So if arabbit's gene string is "ATGC", its W is 1 due to ATGC contains both"ATG"(+4) and "TGC"(-3). And if another rabbit's genestring is "ATGATG", its W is 4 due to one gene segment can becalculate only once.
Because there are enough rabbits on Earth before 2012, so we can assume we canget any genes with different structure. Now Dr. X want to find a rabbit whosegene has highest W value. There are so many different genes with length l, andDr. X is not good at programming, can you help him to figure out the W value ofthe best rabbit.

Input

There are multipletest cases. For each case the first line is two integers n (1 ≤ n ≤ 10)l (1 ≤ l ≤ 100), indicating the number of theparticular 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 arabbit's W.

Output

For each testcase, output an integer indicating the W value of the best rabbit. If we foundthis 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 after2012!

Hint

case 1we can find a rabbit whose gene string is ATGG(4), orATGA(4) etc.

case 2we can find a rabbit whose gene string is TGCTGC(4), orTGCCCC(4) etc.

case 3any gene string whose length is 1 has a negative W.

Author

HONG, Qize

Source

2011 Asia Dalian Regional Contest 



        大致题意,还是类似,给你一些字符串,这些字符串有相应的权值,只要包含某个字符串就要加上这个权值。然后同样也是A、T、C和G四个DNA,再告诉你一个长度,问你这个长度的所有字符串中,权值和最大能够到达多少。

        一开始的想法还是和之前类似,我们之前有记录单词结尾,我们现在在记录单词结尾的时候把单词的权值也给记上,然后转移的时候,转移最大值。有转移方程dp[i][j]=max(dp[i][j],dp[i-1][x]+val[x]),这个val[x]包含的不止一个单词的结尾的权值,因为单词有相互包含的关系。但是这里却有一个很大的缺陷,那就是题目要求一个单词的权值只能够计算一次,而这个转移方程中体现的确是可以多次相加。

        所以我们得另辟蹊径,看到这个单词数量只有10个,很容易想到状态压缩,但是如果用0、1来表示是否构成某一个单词然后dp数组保存最大值,这个字符的关系又如何处理呢?答案是,我们的dp方程不保存最大值,只保存一个存在性的判定。即dp[i][j][k]表示走了i步,到了AC自动机中的第j个点,然后当前单词取到的状态是k,这个状态是否能够达到。最后,在所有可达状态中,我们根据这个单词权值和来确定最大值。于是可以有转移方程:dp[i][x][k|st[x]] |= dp[i-1][j][k],其中x是j的其中一个后记节点。可以看出,里面的st[x]表示,在AC自动机中的x点处可以包含的所有单词的状态。因此,我们在AC自动机中原本保存的单词结尾位置,就要相应的改为单词的二进制存在形式。在转移完毕后,我们暴力所有可达状态,求出最大值即可。

        另外,本题数据并不小,需要用到滚动数组。具体见代码:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define N 1010

using namespace std;

bool dp[2][N][1<<10];
int h[99],val[N];

struct AC_automation
{
    struct node{int fail,st,ch[4];}T[N];
    int tot,root;

    void init()
    {
        tot=root=0;
        memset(T,0,sizeof(T));
    }

    void ins(unsigned char* x,int st)
    {
        int o=root;
        for(int k=0;x[k];k++)
        {
            int c=h[x[k]];
            if(!T[o].ch[c]) T[o].ch[c]=++tot;
            o=T[o].ch[c];
        }
        T[o].st|=1<<st;
    }

    void get_fail()
    {
        queue<int> q;
        q.push(root);
        while(!q.empty())
        {
            int o=q.front();
            T[o].st|=T[T[o].fail].st;
            for(int i=0;i<4;i++)
            {
                if (!T[o].ch[i])
                {
                    T[o].ch[i]=T[T[o].fail].ch[i];
                    continue;
                }
                if (o!=root)
                {
                    int fa=T[o].fail;
                    while(fa&&!T[fa].ch[i]) fa=T[fa].fail;
                    T[T[o].ch[i]].fail=T[fa].ch[i];
                } else T[T[o].ch[i]].fail=root;
                q.push(T[o].ch[i]);
            } q.pop();
        }
    }

} AC;

int main()
{
    int n,m;
    h['A']=0; h['T']=1;
    h['C']=2; h['G']=3;
    while(~scanf("%d%d",&n,&m))
    {
        AC.init();
        unsigned char s[110];
        for(int i=0;i<n;i++)
        {
            scanf("%s",s);
            scanf("%d",&val[i]);
            AC.ins(s,i);
        }
        AC.get_fail();
        memset(dp[0],0,sizeof(dp[0]));
        dp[0][0][0]=1;
        for(int i=1;i<=m;i++)
        {
            memset(dp[i&1],0,sizeof(dp[i&1]));
            for(int j=0;j<=AC.tot;j++)
                for(int k=0;k<(1<<n);k++)
                    if (dp[(i+1)&1][j][k])
                        for(int p=0;p<4;p++)
                        {
                            int x=AC.T[j].ch[p];
                            dp[i&1][x][k|AC.T[x].st]=1;
                        }
        }
        int ans=-INF;
        for(int i=0;i<=AC.tot;i++)
            for(int j=0;j<(1<<n);j++)
                if (dp[m&1][i][j])
                {
                    int res=0;
                    for(int k=0;k<n;k++)
                        if (j&(1<<k)) res+=val[k];
                    ans=max(ans,res);
                }
        if (ans<0) puts("No Rabbit after 2012!");
                        else printf("%d\n",ans);
    }
    return 0;
}


        这种类型的状态压缩不仅在AC自动机中,在其他地方也可以用到,即用dp转移状态的可达性,最后在所有可达状态中找最优,值得借鉴。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值