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

在2012年的背景下,生物学家Dr.X致力于寻找拥有最高基因权重值的兔子,通过分析基因序列中的特定片段来评估兔子的价值。通过编程解决复杂问题,旨在在有限的时间内找到最优解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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: zchao1995@gmail.com 
    > 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值