ZOJ3545---Rescue the Rabbit(AC自动机+dp)

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.

Author: HONG, Qize

Contest: The 2011 ACM-ICPC Asia Dalian Regional Contest

还是很简单的一题dp, dp[i][j][k]表示长度为i,在节点j,状态为k的可行性,然后建立自动机转移就行,数组开不下,所以要用滚动数组,但是记得用滚动数组时,上次用的不能干扰到这次用的

/*************************************************************************
    > File Name: ZOJ3545.cpp
    > Author: ALex
    > Mail: [email protected]
    > Created Time: 2015年04月20日 星期一 15时42分47秒
 ************************************************************************/

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <stack>
#include <map>
#include <bitset>
#include <set>
#include <vector>

using namespace std;

const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double eps = 1e-15;
typedef long long LL;
typedef pair <int, int> PLL;

const int MAX_NODE = 1010;
const int CHILD_NUM = 4;

bool dp[2][MAX_NODE][1100];
int  mp[15];

struct AC_Automation
{
    int next[MAX_NODE][CHILD_NUM];
    int fail[MAX_NODE];
    int end[MAX_NODE];
    int root, L;

    int newnode()
    {
        for (int i = 0; i < CHILD_NUM; ++i)
        {
            next[L][i] = -1;
        }
        end[L++] = 0;
        return L - 1;
    }

    void init ()
    {
        L = 0;
        root = newnode();
    }

    int ID(char c)
    {
        if (c == ‘A‘)
        {
            return 0;
        }
        if (c == ‘G‘)
        {
            return 1;
        }
        if (c == ‘T‘)
        {
            return 2;
        }
        return 3;
    }

    void Build_Trie (char buf[], int id)
    {
        int now = root;
        int len = strlen (buf);
        for (int i = 0; i < len; ++i)
        {
            if (next[now][ID(buf[i])] == -1)
            {
                next[now][ID(buf[i])] = newnode();
            }
            now = next[now][ID(buf[i])];
        }
        end[now] |= (1 << id);
    }

    void Build_AC ()
    {
        queue <int> qu;
        fail[root] = root;
        for (int i = 0; i < CHILD_NUM; ++i)
        {
            if (next[root][i] == -1)
            {
                next[root][i] = root;
            }
            else
            {
                fail[next[root][i]] = root;
                qu.push (next[root][i]);
            }
        }
        while (!qu.empty())
        {
            int now = qu.front();
            qu.pop();
            end[now] |= end[fail[now]];
            for (int i = 0; i < CHILD_NUM; ++i)
            {
                if (next[now][i] == -1)
                {
                    next[now][i] = next[fail[now]][i];
                }
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    qu.push(next[now][i]);
                }
            }
        }
    }

    void solve(int l, int n)
    {
        memset(dp, 0, sizeof(dp));
        dp[0][0][0] = 1;
        int now = 1;
        for (int i = 0; i < l; ++i)
        {
            memset(dp[now], 0, sizeof(dp[now]));
            for (int j = 0; j < L; ++j)
            {
                for (int k = 0; k < (1 << n); ++k)
                {
                    for (int q = 0; q < 4; ++q)
                    {
                        int nxt = next[j][q];
                        dp[now][nxt][k | end[nxt]] = (dp[now][nxt][k | end[nxt]] || dp[now ^ 1][j][k]);
                    }
                }
            }
            now ^= 1;
        }
        int ans = -inf;
        for (int i = 0; i < L; ++i)
        {
            for (int j = 0; j < (1 << n); ++j)
            {
                if (dp[now ^ 1][i][j])
                {
                    int w = 0;
                    for (int k = 0; k < n; ++k)
                    {
                        if (j & (1 << k))
                        {
                            w += mp[k];
                        }
                    }
                    ans = max(ans, w);
                }
            }
        }
        if (ans < 0)
        {
            printf("No Rabbit after 2012!\n");
        }
        else
        {
            printf("%d\n", ans);
        }
    }
}AC;

char str[110];

int main()
{
    int n, l, w;
    while (~scanf("%d%d", &n, &l))
    {
        AC.init();
        for (int i = 0; i < n; ++i)
        {
            scanf("%s%d", str, &w);
            AC.Build_Trie(str, i);
            mp[i] = w;
        }
        AC.Build_AC();
        AC.solve(l, n);
    }
    return 0;
}

时间: 2024-08-09 13:39:16

ZOJ3545---Rescue the Rabbit(AC自动机+dp)的相关文章

HDU 4057 Rescue the Rabbit (AC自动机+DP)

http://acm.hdu.edu.cn/showproblem.php?pid=4057 Rescue the Rabbit Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1482    Accepted Submission(s): 430 Problem Description Dr. X is a biologist,

Zoj 3545 Rescue the Rabbit(ac自动机+dp)

题目大意: 给出的DNA序列有一个权值,请构造一个长度为I的DNA序列使得在这段DNA序列的权值最大.如果为负数就输出噼里啪啦... 思路分析: 构造序列就是在ac自动机上走,求最大要用到dp dp[i][j][k] 表示现在构造到了长度 i .此时的我们把当前字符放在j节点,并且满足了k状态.k是一个10位的2进制状态压缩. 注意这道题上有坑就是一个序列可能有多个权值.所以不能直接赋值,需要用位或. #include <cstdio> #include <iostream> #i

hdu 4057 Rescue the Rabbit(AC自动机+状压dp)

题目链接:hdu 4057 Rescue the Rabbit 题意: 给出一些模式串,每个串有一定的价值,现在构造一个长度为M的串,问最大的价值为多少,每个模式串最多统计一次. 题解: 由于每个模式串最多统计一次,所以我们要考虑记录是否已经存在该串. 考虑dp[i][j][k]表示当前考虑到i的长度,存在的串的组合为j,在AC自动机上走到了k这个节点的状态. 然后转移一下就能将所有能到达的状态走到.然后取一个最大值就行了. 1 #include<bits/stdc++.h> 2 #defin

hdu4057Rescue the Rabbit(ac自动机+dp)

链接 当时是因为没有做出来这道题才开了自动机的专题,现在看看还是比较简单的. 因为每个病毒串只算一次,只有10个病毒串,可以状压一下哪些状态是可以达到的,最后取一个最大值. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #includ

HDU3341 Lost&#39;s revenge(AC自动机+DP)

题目是给一个DNA重新排列使其包含最多的数论基因. 考虑到内存大概就只能这么表示状态: dp[i][A][C][G][T],表示包含各碱基个数为ACGT且当前后缀状态为自动机第i的结点的字符串最多的数论基因数 其中ACGT可以hash成一个整数(a*C*G*T+c*G*T+g*T+T),这样用二维数组就行了,而第二维最多也就11*11*11*11个. 接下来转移依然是我为人人型,我是丢进一个队列,用队列来更新状态的值. 这题果然挺卡常数的,只好手写队列,最后4500msAC,还是差点超时,代码也

poj 1625 Censored!(AC自动机+DP+高精度)

题目链接:poj 1625 Censored! 题目大意:给定N,M,K,然后给定一个N字符的字符集和,现在要用这些字符组成一个长度为M的字符串,要求不包 括K个子字符串. 解题思路:AC自动机+DP+高精度.这题恶心的要死,给定的不能匹配字符串里面有负数的字符情况,也算是涨姿势 了,对应每个字符固定偏移128单位. #include <cstdio> #include <cstring> #include <queue> #include <vector>

HDU 2296 Ring AC自动机 + DP

题意:给你n个模式串,每个模式串有一个得分,让你构造出一个长度为N之内且分数最高的文本串;输出字典序列最小的. 解题思路:  AC自动机 + DP , 不过要输出字典序列最小,多开一个 一个三维字符串来辅助二维DP(新思路) , DP[i][j] ,表示到i位置状态为j的最大得分. 解题代码: 1 // File Name: temp.cpp 2 // Author: darkdream 3 // Created Time: 2014年09月11日 星期四 15时18分4秒 4 5 #inclu

HDU2296——Ring(AC自动机+DP)

题意:输入N代表字符串长度,输入M代表喜欢的词语的个数,接下来是M个词语,然后是M个词语每个的价值.求字符串的最大价值.每个单词的价值就是单价*出现次数.单词可以重叠.如果不止一个答案,选择字典序最小的. 题解:AC自动机+dp.dp[i][j]表示在字符串长度i,在自动机的第j个状态.因为要字典序最小,所以转移时要保持字典序最小. 想了各种转移姿势 最后还是查了题解 发现可以直接记录前缀转移…… #include <bits/stdc++.h> using namespace std; co

hdu 2296 aC自动机+dp(得到价值最大的字符串)

Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3180    Accepted Submission(s): 1033 Problem Description For the hope of a forever love, Steven is planning to send a ring to Jane with a rom