DNA repair 【HDU - 2457】【AC自动机+DP思路】

版权声明:https://blog.csdn.net/qq_41730082 https://blog.csdn.net/qq_41730082/article/details/86612152

题目链接


  开始肝这道题的时候也是冒了十足的勇气……呜呜呜,当时一直没发现,我有个地方写成了"s[i] - 'A'",怎么能这样用啊!毕竟只有A、C、G、T的说……呜呜呜…… QAQ

  然后讲一下,这道题的AC自动机的想法,还有DP的思路(我DP超菜…… 能过也是超神了……),我们在这用AC自动机来做的是去取状态,那么怎么取状态?我们先按照普遍的写法(AC自动机上建满路,下一步到达A、C、G、T全都要),然后去推前一刻的状态,用dp[0][0]表示0初始状态,然后去不断的往下递推待查询的那个模式串,要求是这样的,如果遇到的是病毒感染状态,那么就是不能要的状态,就不去更新它了(故除0初始状态以外,都赋为最大值点),如果目前不是病毒状态,我们去看,它可以改变成除了它以外的另外的状态(不一定是满的3个,因为有可能会从健康态变成病毒态),然后,若是改变原先的字符串,就要在之前的那一步上"+1",多了一步改变;若是发现是相等的,那么就不需要改变,去取最小值即可(因为可能存在不同的状态递推到这个点的状态)。

  然后AC自动机上怎么写?我们存储全部的状态,包括那些个不在字符串上的额外的状态,然后用一个静态数组去存它们,大致会有最多1000组的状态吧,把状态记录下来,然后在DP的时候去用到就可以了,主要是反映出前一刻的状态之用(此时的AC自动机的主要用途)。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <cstdlib>
#include <ctime>
#include <unordered_map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1005;
unordered_map<char, int> dir;
inline void pre_did() { dir['A'] = 0;   dir['C'] = 1;   dir['G'] = 2;   dir['T'] = 3; }
int N, num, dp[maxN][maxN], ans;
char virus[55], test[maxN];
struct node
{
    node *next[4];
    node *fail;
    int flag, id;
    node()
    {
        for(int i=0; i<4; i++) next[i] = NULL;
        fail = NULL;
        flag = id = 0;
    }
}tree[maxN];
node *root;
node *new_node()
{
    node *p = &tree[num];
    for(int i=0; i<4; i++) p->next[i] = NULL;
    p->fail = NULL;
    p->flag = 0;
    p->id = num++;
    return p;
}
void update(char *s)
{
    node *temp = root;
    int len = (int)strlen(s);
    for(int i=0; i<len; i++)
    {
        int x = dir[s[i]];
        if(temp->next[x] == NULL) temp->next[x] = new_node();
        temp = temp->next[x];
    }
    temp->flag = 1;
}
void build_fail()
{
    queue<node *> Q;
    Q.push(root);
    node *temp;
    while(!Q.empty())
    {
        temp = Q.front();   Q.pop();
        for(int i=0; i<4; i++)
        {
            if(temp->next[i])
            {
                if(temp == root) temp->next[i]->fail = root;
                else
                {
                    node *p = temp->fail;
                    while(p)
                    {
                        if(p->next[i]) { temp->next[i]->fail = p->next[i];  break; }
                        p = p->fail;
                    }
                    if(!p) temp->next[i]->fail = root;
                    if(temp->next[i]->fail->flag) temp->next[i]->flag = 1;
                }
                Q.push(temp->next[i]);
            }
            else temp->next[i] = (temp == root ? root : temp->fail->next[i]);
        }
    }
}
void AC_auto(char *s)
{
    ans = INF;  memset(dp, INF, sizeof(dp));
    dp[0][0] = 0;
    int len = (int)strlen(s);
    for(int i=0; i<len; i++)
    {
        for(int j=0; j<num; j++)
        {
            for(int k=0; k<4; k++)
            {
                if(tree[j].next[k]->flag) continue;
                int x = dir[s[i]];
                if(x == k)
                {
                    dp[i+1][tree[j].next[k]->id] = min(dp[i][j], dp[i+1][tree[j].next[k]->id]);
                }
                else
                {
                    dp[i+1][tree[j].next[k]->id] = min(dp[i][j] + 1, dp[i+1][tree[j].next[k]->id]);
                }
            }
        }
    }
    for(int i=0; i<num; i++) ans = min(ans, dp[len][i]);
    if(ans >= INF) ans = -1;
}
inline void init()
{
    num = 0;
    root = new_node();
}
int main()
{
    pre_did();
    int Cas = 0;
    while(scanf("%d", &N) && N)
    {
        init();
        for(int i=1; i<=N; i++)
        {
            scanf("%s", virus);
            update(virus);
        }
        build_fail();
        scanf("%s", test);
        AC_auto(test);
        printf("Case %d: %d\n", ++Cas, ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/86612152