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 namespace std;

const int INF = 0x3f3f3f3f;
struct Trie{
    int next[60010][2], fail[60010], end[60010];
    int root, L;
    int newnode(){
        for(int i=0; i<2; i++)  next[L][i] = -1;
        end[L++] = 0;
        return L-1;
    }
    void init(){
        L = 0;
        root = newnode();
    }
    void insert(char buf[], int id){
        int len = strlen(buf);
        int now = root;
        for(int i=0; i<len; i++){
            if(next[now][buf[i] - '0'] == -1)
                next[now][buf[i] - '0'] = newnode();
            now = next[now][buf[i] - '0'];
        }
        end[now] = id;
    }
    void build(){
        queue<int> Q;
        fail[root] = root;
        for(int i=0; i<2; i++)
            if(next[root][i] == -1) next[root][i] = root;
            else{
                fail[ next[root][i] ] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty()){
            int now = Q.front();
            Q.pop();
            if(end[ fail[now] ] == -1) end[now] = -1;
            else end[now] |= end[ fail[now] ];
            for(int i=0; i<2; i++)
                if(next[now][i] == -1)  next[now][i] = next[ fail[now] ][i];
                else{
                    fail[ next[now][i] ] = next[ fail[now] ][i];
                    Q.push(next[now][i]);
                }
        }
    }
    int g[11][11];
    int dp[1025][11];
    int cnt;
    int pos[11];
    int dis[60010];

    void bfs(int k){
        queue<int> q;
        memset(dis, -1, sizeof(dis));
        dis[pos[k]] = 0;
        q.push(pos[k]);
        while(!q.empty()){
            int now = q.front();
            q.pop();
            for(int i=0; i<2; i++){
                int tmp = next[now][i];
                if(dis[tmp] < 0 && end[tmp] >= 0){
                    dis[tmp] = dis[now] + 1;
                    q.push(tmp);
                }
            }
        }
        for(int i=0; i<cnt; i++)    g[k][i] = dis[pos[i]];
    }

    int solve(int n){
        pos[0] = 0;
        cnt = 1;
        for(int i=0; i<L; i++)
            if(end[i] > 0) pos[cnt++] = i;
        for(int i=0; i<cnt; i++) bfs(i);

        for(int i=0; i<(1<<n); i++)
            for(int j=0; j<cnt; j++)
                dp[i][j] = INF;
        dp[0][0] = 0;
        for(int i=0; i<(1<<n); i++)
            for(int j=0; j<cnt; j++)
                if(dp[i][j] < INF){
                    for(int k=0; k<cnt; k++){
                        if(g[j][k] < 0) continue;
                        if(j == k) continue;
                        dp[i | end[pos[k]]][k] = min(dp[i | end[pos[k]]][k], dp[i][j] + g[j][k]);
                    }
                }
        int ans = INF;
        for(int i=0; i<cnt; i++)
            ans = min(ans, dp[(1<<n)-1][i]);
        return ans;
    }
};

char buf[1010];
Trie ac;

int main(){
    #ifdef sxk
        freopen("in.txt", "r", stdin);
    #endif // sxk
    int n, m;
    while(scanf("%d%d", &n, &m) == 2){
        if(n == 0 && m == 0) break;
        ac.init();
        for(int i=0; i<n; i++){
            scanf("%s", buf);
            ac.insert(buf, 1<<i);
        }
        for(int i=0; i<m; i++){
            scanf("%s", buf);
            ac.insert(buf, -1);
        }
        ac.build();
        printf("%d\n", ac.solve(n));
    }
    return 0;
}

版权声明:本文为sxk原创文章,转载请附加本文链接^_^

时间: 2024-12-27 14:26:12

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)

题目链接:hdu 3247 Resource Archiver 题目大意:给定N个需要包含的串,M个不能包含的串,问说满足的最短字符串长度. 解题思路:直接对所有串建立AC自动机,不能满足的串用同一种标记即可.然后处理出所有属于需要包含串的单词节 点,用BFS处理出两两之间的距离,并且过程中是不能经过禁止节点.这样做的原因是节点的个数很多,如果对所有的 节点进行dp的话空间都不够.剩下的就是dp了. #include <cstdio> #include <cstring> #inc

[dp专题] AC自动机与状态压缩dp的结合

最近做到好几道关于AC自动机与状态压缩dp的结合的题,这里总结一下. 题目一般会给出m个字符串,m不超过10,然后求长度为len并且包含特定给出的字符串集合的字符串个数. 以HDU 4758为例: 把题意抽象为:给出两个字符串,且只包含两种字符 'R'.'D',现在求满足下列条件的字符串个数:字符串长度为(m+n),其中包含n个'D',m个'R'. 如果不用AC自动机来做,这道题还真没法做了,因为不管怎样都找不到正确的dp状态转移方程. 而如果引入AC自动机,把在AC自动机上的结点当做dp的一个

【HDU2825】Wireless Password【AC自动机,状态压缩DP】

题意 题目给出m(m<=10)个单词,每个单词的长度不超过10且仅由小写字母组成,给出一个正整数n(n<=25)和正整数k,问有多少方法可以组成长度为n的文本且最少包含k个给出的单词. 分析 和上一个AC自动机很相似,上一篇博客是不包含任何一个单词长度为n的方案数,这个题是包含至少k个单词的方案数,而且n,m,k都非常的小. 按照前面的经验很容易想到,我们还是得先建一个AC自动机,然后把它的单词结点标记出来.与前面不同的是我们在状态转移的时候需要考虑到当前走过的结点已经包含多少单词了.所以我们

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

HDU 1565 方格取数(1) (状态压缩DP)

HDU 1565 方格取数(1) (状态压缩DP) ACM 题目地址: HDU 1565 方格取数(1) 题意: 中文. 分析: dp[i][j]表示前i行状态j的最优解. 先预处理出符合条件的数,17000+个(n在20以内). 不过感觉复杂度挺高的会T,但是却能A. 这题的正解应该是最小割,回头补下. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * File: 1565_dp.cpp * Create Date: 2014-09-19 23

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 3502 bfs+状态压缩dp

题意是给你n*m的矩阵     每个单位有一个数,-1表示不能走   >=0表示有有多少个能量能获得    问从左上角到右下角能获得的做大能量值(走一步消耗1单位能量) 思路:  先bfs求出所有线之间的最短距离(当然  有用的只有有能量值的点和起点,终点) 然后状态压缩dp  找到最大能量值    这里有几个注意的地方 状态尽量从1开始    减少数组的空间(爆了一次)   其次是bfs是只搜有能量的点     其它都差不多: #include<stdio.h> #include<

hdu - 1429 胜利大逃亡(续) (bfs状态压缩)

http://acm.hdu.edu.cn/showproblem.php?pid=1429 终于开始能够做状态压缩的题了,虽然这只是状态压缩里面一道很简单的题. 状态压缩就是用二进制的思想来表示状态. 总共有10种钥匙,那么开一个(1<<10 的数组) 那么每次遇到一把钥匙我就用当前状态 |  钥匙转化为2进制的数值,然后遇到门的时候判断是否有对应的钥匙,只要用当前状态 & 门转化为2进制的值就可以.初始为0时,state=0,表示10个状态位都是0.那么每次遇到钥匙就改变相应的状态