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 namespace std;
 4
 5 const int AC_N=1e5+7,tyn=2;
 6 struct AC_automation{
 7     int tr[AC_N][tyn],so[AC_N],v[AC_N],Q[AC_N],fail[AC_N],tot;
 8     inline int getid(char x){return x-‘0‘;}
 9     void nw(){so[++tot]=0,fail[tot]=0,v[tot]=0;memset(tr[tot],0,sizeof(tr[tot]));}
10     void init(){tot=-1,fail[0]=-1,nw();}
11     void insert(char *s,int idx,int fg,int x=0){
12         for(int len=strlen(s),i=0,w;i<len;x=tr[x][w],i++)
13             if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot;
14         if(fg)so[x]=1<<idx;else v[x]=1;
15     }
16     void build(int head=1,int tail=0){
17         for(int i=0;i<tyn;i++)if(tr[0][i])Q[++tail]=tr[0][i];
18         while(head<=tail)for(int x=Q[head++],i=0;i<tyn;i++)
19             if(tr[x][i])fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i],
20             so[tr[x][i]]|=so[tr[fail[x]][i]],v[tr[x][i]]+=v[tr[fail[x]][i]];
21             else tr[x][i]=tr[fail[x]][i];
22     }
23
24 }AC;
25
26 char s[AC_N];
27 int path[205][205],pos[205],dp[1<<10][205],cnt,Q[AC_N],dis[AC_N],n,m;
28
29 inline void up(int &a,int b){if(a>b)a=b;}
30
31 void bfs(int u,int head=1,int tail=0)
32 {
33     memset(dis,-1,sizeof(dis));
34     Q[++tail]=pos[u],dis[pos[u]]=0;
35     while(head<=tail)
36     {
37         int now=Q[head++];
38         F(i,0,1)
39         {
40             int q=AC.tr[now][i];
41             if(dis[q]<0&&!AC.v[now])dis[q]=dis[now]+1,Q[++tail]=q;
42         }
43     }
44     F(i,0,cnt)path[u][i]=dis[pos[i]];
45 }
46
47 void fuck()//TSP的dp
48 {
49     memset(dp,-1,sizeof(dp)),dp[0][0]=0;
50     for(int i=0;i<(1<<n);i++)F(j,0,cnt)if(dp[i][j]>=0)F(k,0,cnt)if(path[j][k]>=0)
51     if(dp[i|AC.so[pos[k]]][k]==-1)dp[i|AC.so[pos[k]]][k]=dp[i][j]+path[j][k];
52     else up(dp[i|AC.so[pos[k]]][k],dp[i][j]+path[j][k]);
53     int ans=INT_MAX;
54     F(i,0,cnt)if(dp[(1<<n)-1][i]!=-1)up(ans,dp[(1<<n)-1][i]);
55     printf("%d\n",ans==INT_MAX?-1:ans);
56 }
57
58 int main()
59 {
60     while(~scanf("%d%d",&n,&m)&&n+m)
61     {
62         AC.init(),cnt=0;
63         F(i,0,n-1)scanf("%s",s),AC.insert(s,i,1);
64         F(i,0,m-1)scanf("%s",s),AC.insert(s,i,0);
65         AC.build();
66         F(i,1,AC.tot)if(AC.so[i])pos[++cnt]=i;
67         F(i,0,cnt)bfs(i);//求出0到所以资源串的距离和资源串到资源串之间的距离
68         fuck();
69     }
70     return 0;
71 }

时间: 2024-10-11 21:00:13

hdu_3247_Resource Archiver(AC自动机+bfs+TSP)的相关文章

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

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

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)

Description Great! Your new software is almost finished! The only thing left to do is archiving all your n resource files into a big one. Wait a minute- you realized that it isn't as easy as you thought. Think about the virus killers. They'll find yo

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片段的

【BZOJ2085】【Poi2010】Hamsters AC自动机bfs+倍增floyd

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45747235"); } 题解: 首先我们搞个 AC 自动机,然后每个串在 AC 自动机上 bfs 求出 f(i,j) 表示串 i 后面最少接 f(i,j) 个字母能搞出来串 j . 然后把每个串当成一个点,倍增 floyd 求两点之

Bzoj1195 [HNOI2006]最短母串 [AC自动机]

Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1304  Solved: 439 Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的长度不超过50. Output 只有一行,为找到的最短的字符串T.在保证最短的前提下,如果

【BZOJ】1030: [JSOI2007]文本生成器(递推+ac自动机)

http://www.lydsy.com/JudgeOnline/problem.php?id=1030 其实做了1009也不会感到很难了,无非将kmp变成了ac自动机. 设f[i,j]表示前i个串当前匹配到j的节点的方案数.. 然后自己想. sb错1:ac自动机的节点开小了(自己想错了..以为最多节点就是层数×分支(26)....于是..其实是n个串的长度和...) sb错2:ac自动机bfs时没有维护信息啊!!只维护了一个fail... #include <cstdio> #include

Keywords Search HDU2222 AC自动机模板题

ac自动机说起来很复杂,其实和kmp是一样的思路,都是寻找相同前后缀,减少跳的次数.只要理解了kmp是怎么求next数组的,ac自动机bfs甚至比knp还好写. 这里大致说一下kmp求next数组的方法吧,假设现在要求第c个字符的next值(假设这个c很大,这样画图出来比较清晰方便理解),因为遍历过程中我们已经知道了第c-1个字符的next为x(假设比c小很多),即next[c-1] = x.那就代表我们知道了a[1]-a[x]这一段和a[c-1-x]-a[c-1]这一段是相等的对吧. 那么现在