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 your software suspicious, if your software contains one of the m predefined virus codes. You absolutely don’t want this to happen. 
Technically, resource files and virus codes are merely 01 strings. You’ve already convinced yourself that none of the resource strings contain a virus code, but if you make the archive arbitrarily, virus codes can still be found somewhere. 
Here comes your task (formally): design a 01 string that contains all your resources (their occurrences can overlap), but none of the virus codes. To make your software smaller in size, the string should be as short as possible.

Input

There will be at most 10 test cases, each begins with two integers in a single line: n and m (2 <= n <= 10, 1 <= m <= 1000). The next n lines contain the resources, one in each line. The next m lines contain the virus codes, one in each line. The resources and virus codes are all non-empty 01 strings without spaces inside. Each resource is at most 1000 characters long. The total length of all virus codes is at most 50000. The input ends with n = m = 0.

Output

For each test case, print the length of shortest string.

Sample Input

2 2
1110
0111
101
1001
0 0

Sample Output

5

题目大意:给n个资源01串和m个病毒01串。构造一个最短的01串使其包含所有的资源串,但不包含任何一个病毒串。题目分析:建立好AC自动机后,在上面广搜即可。

代码如下:
# include<iostream>
# include<cstdio>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std;

const int N=10000;

int ch[6*N+5][2];
int fail[6*N+5];
int sz,type[6*N+5];

void init()
{
	sz=0;
	memset(ch,-1,sizeof(ch));
	memset(type,0,sizeof(type));
}

int idx(char c)
{
	return c-‘0‘;
}

void insert(char *s,int val)
{
	int r=0;
	int n=strlen(s);
	for(int i=0;i<n;++i){
		int c=idx(s[i]);
		if(ch[r][c]==-1) ch[r][c]=++sz;
		r=ch[r][c];
	}
	type[r]=val;
}

void getFail()
{
	queue<int>q;
	fail[0]=0;
	for(int i=0;i<2;++i){
		if(ch[0][i]==-1)
			ch[0][i]=0;
		else{
			q.push(ch[0][i]);
			fail[ch[0][i]]=0;
		}
	}
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		if(type[fail[u]]>0)
			type[u]|=type[fail[u]];
		for(int i=0;i<2;++i){
			if(ch[u][i]==-1)
				ch[u][i]=ch[fail[u]][i];
			else{
				fail[ch[u][i]]=ch[fail[u]][i];
				q.push(ch[u][i]);
			}
		}
	}
}

struct Node
{
	int step;
	int loca;
	int sta;
};
int n,m;
char s[1005];
char vis[6*N+5][1<<10];

int bfs()
{
	queue<Node>q;
	memset(vis,0,sizeof(vis));
	q.push(Node{0,0,0});
	while(!q.empty())
	{
		Node u=q.front();
		q.pop();
		if(u.sta==(1<<n)-1)
			return u.step;
		for(int i=0;i<2;++i) if(type[ch[u.loca][i]]>=0){
			int v=ch[u.loca][i];
			if(vis[v][u.sta|type[v]]) continue;
			vis[v][u.sta|type[v]]=1;
			q.push(Node{u.step+1,v,u.sta|type[v]});
		}
	}
	return -1;
}

int main()
{
	while(~scanf("%d%d",&n,&m)&&(n+m))
	{
		init();
		for(int i=0;i<n;++i){
			scanf("%s",s);
			insert(s,1<<i);
		}
		for(int i=0;i<m;++i){
			scanf("%s",s);
			insert(s,-1);
		}
		getFail();
		printf("%d\n",bfs());
	}
	return 0;
}

  


时间: 2024-10-29 19:06:12

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

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 + 状态压缩DP)

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

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

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

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

HDU 2896 病毒侵袭 AC自动机题解

本题是在text里面查找key word的增强版,因为这里有多个text. 那么就不可以简单把Trie的叶子标志记录修改成-1进行加速了,可以使用其他技术,我直接使用个vis数组记录已经访问过的节点,达到加速效果,速度还算挺快的. 不过看discuss里面有人直接使用Trie,做出了140ms的速度,而且他的程序严格来说并不正确,可见本题的数据很水啊.Trie的时间效率肯定比AC自动机低,但是在数据很水的特殊情况下,Trie的速度也可以很快的. 注意两个细节: 1 病毒也需要安装顺序输出,不小心

hdu 2896 病毒侵袭 AC自动机(查找包含哪些子串)

病毒侵袭 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 19465    Accepted Submission(s): 4814 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋——我们能在有生之年看到500年一遇的世界奇观,那是多么幸福的事儿

HDU 2222 Keyword Search AC自动机模板

#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <stack> #include <map> #include <ctime> #include <io

hdu 2825 Wireless Password(ac自动机&amp;dp)

Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4022    Accepted Submission(s): 1196 Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there