hdu 3247 Resource Archiver(AC自动机+BFS+DP)

题目链接:hdu 3247 Resource Archiver

题目大意:给定N个需要包含的串,M个不能包含的串,问说满足的最短字符串长度。

解题思路:直接对所有串建立AC自动机,不能满足的串用同一种标记即可。然后处理出所有属于需要包含串的单词节

点,用BFS处理出两两之间的距离,并且过程中是不能经过禁止节点。这样做的原因是节点的个数很多,如果对所有的

节点进行dp的话空间都不够。剩下的就是dp了。

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

typedef pair<int,int> pii;
const int maxn = 100005;
const int maxm = 1005;
const int sigma_size = 2;
const int inf = 0x3f3f3f3f;

struct Aho_Corasick {
    int sz, g[maxn][sigma_size];
    int tag[maxn], fail[maxn], vis[maxn];

    void init();
    int idx(char ch);
    void insert(char* str, int k);
    void getFail();
    void match(char* str);
    void put(int x, int y);

    queue<int> que;
    int K, pos[maxm], dis[maxn];
    int dp[maxm][1030], d[maxm][maxm];

    int solve();
    void BFS(int s);
    int DP();
}AC;

int N, M;
char w[1005];

int main () {
    while (scanf("%d%d", &N, &M) == 2 && N + M) {
        AC.init();
        for (int i = 1; i <= N; i++) {
            scanf("%s", w);
            AC.insert(w, i);
        }
        for (int i = 1; i <= M; i++) {
            scanf("%s", w);
            AC.insert(w, 0);
        }
        printf("%d\n", AC.solve());
    }
    return 0;
}

int Aho_Corasick::DP() {
    int E = (1<<N)-1;
    memset(dp, inf, sizeof(dp));
    dp[0][0] = 0;

    for (int i = 0; i < E; i++) {
        for (int u = 0; u < K; u++) {
            if (dp[u][i] == inf)
                continue;

            for (int v = 0; v < K; v++) {
                if (d[u][v] == inf)
                    continue;

                int s = i | (tag[pos[v]]>>1);
                dp[v][s] = min(dp[v][s], dp[u][i] + d[u][v]);
            }
        }
    }
    int ans = inf;
    for (int i = 0; i < K; i++)
        ans = min(ans, dp[i][E]);
    return ans;
}

void Aho_Corasick::BFS(int s) {
    memset(dis, inf, sizeof(dis));
    dis[pos[s]] = 0;
    que.push(pos[s]);

    while (!que.empty()) {
        int u = que.front();
        que.pop();

        for (int i = 0; i < sigma_size; i++) {
            int t = u;
            while (t && g[t][i] == 0)
                t = fail[t];
            t = g[t][i];

            if (tag[t]&1)
                continue;
            if (dis[t] > dis[u] + 1) {
                dis[t] = dis[u] + 1;
                que.push(t);
            }
        }
    }
    for (int i = 0; i < K; i++)
        d[s][i] = dis[pos[i]];
}

int Aho_Corasick::solve() {
    getFail();
    K = 0;
    pos[K++] = 0;
    for (int i = 1; i <sz; i++) {
        if (tag[i]>>1)
            pos[K++] = i;
    }
    for (int i = 0; i < K; i++)
        BFS(i);
    return DP();
}

void Aho_Corasick::init() {
    sz = 1;
    tag[0] = 0;
    memset(g[0], 0, sizeof(g[0]));
}

int Aho_Corasick::idx(char ch) {
    return ch - ‘0‘;
}

void Aho_Corasick::put(int x, int y) {
}

void Aho_Corasick::insert(char* str, int k) {
    int u = 0, n = strlen(str);

    for (int i = 0; i < n; i++) {
        int v = idx(str[i]);
        if (g[u][v] == 0) {
            vis[sz] = tag[sz] = 0;
            memset(g[sz], 0, sizeof(g[sz]));
            g[u][v] = sz++;
        }
        u = g[u][v];
    }
    tag[u] = (1<<k);
}

void Aho_Corasick::match(char* str) {
    int n = strlen(str), u = 0;
    for (int i = 0; i < n; i++) {
        int v = idx(str[i]);
        while (u && g[u][v] == 0)
            u = fail[u];

        u = g[u][v];

    }
}

void Aho_Corasick::getFail() {

    for (int i  = 0; i < sigma_size; i++) {
        int u = g[0][i];
        if (u) {
            fail[u] = 0;
            que.push(u);
        }
    }

    while (!que.empty()) {
        int r = que.front();
        que.pop();

        for (int i = 0; i < sigma_size; i++) {
            int u = g[r][i];

            if (u == 0) {
                g[r][i] = g[fail[r]][i];
                continue;
            }

            que.push(u);
            int v = fail[r];
            while (v && g[v][i] == 0)
                v = fail[v];

            fail[u] = g[v][i];
            tag[u] |= tag[fail[u]];
            //last[u] = tag[fail[u]] ? fail[u] : last[fail[u]];
        }
    }
}
时间: 2024-12-19 15:57:47

hdu 3247 Resource Archiver(AC自动机+BFS+DP)的相关文章

HDU 3247 Resource Archiver AC自动机 + bfs + 状态压缩dp

题意:给定你n个文本串 ,m个模式串,怎么构造最短的新的文本串使得这个新的文本串包含n个文本串的所有信息且文本串的长度最短且不包含模式串. 解题思路:这里看题解撸的,首先我们算出两两文本串的距离(end数组标记文本和模式串的值不同,利用这个进行bfs算出两两之间的最短距离,注意到这里模式串的end是不能走到的.这里也不需要松弛操作),然后因为n只有10这么大,所以我们可以状态压缩  ,dp[i][j] 表示 压缩后状态为 i(二进制压缩,每i位表示第i个是否在)且 以j结尾的文本串的最小花费.这

HDU 3247 Resource Archiver (AC自动机 + BFS + 状态压缩DP)

题目链接:Resource Archiver 解析:n个正常的串,m个病毒串,问包含所有正常串(可重叠)且不包含任何病毒串的字符串的最小长度为多少. AC自动机 + bfs + 状态压缩DP 用最短路预处理出状态的转移.可以优化很多 AC代码: #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> using n

HDU 3247 Resource Archiver (AC自己主动机 + BFS + 状态压缩DP)

题目链接:Resource Archiver 解析:n个正常的串.m个病毒串,问包括全部正常串(可重叠)且不包括不论什么病毒串的字符串的最小长度为多少. AC自己主动机 + bfs + 状态压缩DP 用最短路预处理出状态的转移.能够优化非常多 AC代码: #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> us

HDU3247 Resource Archiver(AC自动机+BFS+DP)

题目,求最短的包含所有n个DNA片段且不包含任何一个病毒片段的序列. 容易用所有DNA片段和病毒片段建一个AC自动机,构造fail时处理一下各个结点后缀是DNA或者病毒的情况,然后dp[S][u]表示包含DNA片段的集合是S的且后缀状态是自动机第u个结点的最短序列长度,然后顺着AC自动机避开病毒串转移. 不过构建的AC自动机结点上限60000左右,集合有1024个状态,这样内存开不下.看了题解,原来不必要考虑自动机所有结点—— dp[S][u]表示包含DNA片段集合是S且后缀是第u个DNA片段的

hdu_3247_Resource Archiver(AC自动机+bfs+TSP)

题目链接:hdu_3247_Resource Archiver 题意: 有n个资源串,m个病毒串,现在要将所有的资源串整合到一个串内,并且这个串不能包括病毒串,问最短的串长为多少 题解: 将资源串和病毒串都插入到AC自动机中,分别做好标记,然后用bfs求出0节点和所有资源串互相的最短距离,最后就是一个TSP的状态压缩DP. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespac

HDU 2825 Wireless Password (AC自动机,DP)

http://acm.hdu.edu.cn/showproblem.php?pid=2825 Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4560    Accepted Submission(s): 1381 Problem Description Liyuan lives in a old a

POJ 3691 &amp; HDU 2457 DNA repair (AC自动机,DP)

http://poj.org/problem?id=3691 http://acm.hdu.edu.cn/showproblem.php?pid=2457 DNA repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5690   Accepted: 2669 Description Biologists finally invent techniques of repairing DNA that contain

[AC自动机+spfa+状压dp] hdu 3247 Resource Archiver

题意: 给n个本源串,m个病毒串 求一个最多的长度的单词包含所有的本源串并不包含任意一个病毒串 串均为01串 思路: 只有10个本源串 一开始想的是直接建立完trie图 然后在图上直接spfa 结果发现 dis[60005][1030] 超内存了 这个时候就要想到 其实只有节点的mark值大于0的节点是我们需要用的 就是那些含有状压权值的节点 那么我们先记录下这些节点是哪些 然后发现其实这些不到100个节点 所以跑100遍spfa 求出两两之间的最短路 然后用这个距离 去状压dp 数组就成了 d

HDU 4518 ac自动机+数位dp

吉哥系列故事--最终数 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 304    Accepted Submission(s): 102 Problem Description 在2012年腾讯编程马拉松比赛中,吉哥解决了一道关于斐波那契的题目,这让他非常高兴,也更加燃起了它对数学特别是斐波那契数的热爱.现在,它又在思考一个关于斐波那契