题目链接:https://vjudge.net/problem/HDU-3247

Resource Archiver

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others)
Total Submission(s): 3228    Accepted Submission(s): 1052

Problem 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
 
Source

题意:

给出n个(n<=10)字符串,和m(m<=1000)个单词。求包含所有字符串,并且不包含任何一个单词的长串的最短长度。

题解:

1.看到n的大小为10,并且要求包含所有字符串,就很容易想到用状压DP。

1.1 设dp[status][u]为:当前状态为status(包含了哪些字符串),并且以字符串u结尾的最短长度。设cost[u][v]为:在字符串u后面接上字符串v所需要的最短长度。由于字符串之间可以有重叠,所以cost[u][v]可能小于len[v];由于长串不能包含单词,所以在链接u、v时,之间可能还需要加一些字符以便跳过单词,所以cost[u][v]可能大于len[v]。

1.2 假如求出了cost数组,那么剩下的就是典型TSP问题了。

2. 如何求cost数组呢?

2.1 把n个字符串和m个单词都插入到AC自动机中,并且需要对字符串和单词作相应的标记。

2.2 对于每个字符串,在自动机上跑最短路,求出当前字符串与其他字符串的最短距离,在跑的时候需要跳过单词。原理:AC自动机各个状态之间的关系构成了一张图。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const double EPS = 1e-;
const int INF = 2e9;
const LL LNF = 2e18;
const int MOD = 1e5;
const int MAXN = 5e4+1e4+; int n, m;
int Index[MAXN], pos[MAXN], cost[][], Len[MAXN];
int dp[<<][];
struct Trie
{
int sz, base;
int next[MAXN][], fail[MAXN], end[MAXN];
int root, L;
int newnode()
{
for(int i = ; i<sz; i++)
next[L][i] = -;
end[L++] = false;
return L-;
}
void init(int _sz, int _base)
{
sz = _sz;
base = _base;
L = ;
root = newnode();
}
int insert(char buf[], bool isVirus)
{
int len = strlen(buf);
int now = root;
for(int i = ; i<len; i++)
{
if(next[now][buf[i]-base] == -) next[now][buf[i]-base] = newnode();
now = next[now][buf[i]-base];
}
end[now] = isVirus;
return now;
}
void build()
{
queue<int>Q;
fail[root] = root;
for(int i = ; i<sz; i++)
{
if(next[root][i] == -) next[root][i] = root;
else fail[next[root][i]] = root, Q.push(next[root][i]);
}
while(!Q.empty())
{
int now = Q.front();
Q.pop();
end[now] |= end[fail[now]];
for(int i = ; i<sz; i++)
{
if(next[now][i] == -) next[now][i] = next[fail[now]][i];
else fail[next[now][i]] = next[fail[now]][i], Q.push(next[now][i]);
}
}
} int query()
{
for(int i = ; i<(<<n); i++)
for(int j = ; j<n; j++)
dp[i][j] = INF;
for(int j = ; j<n; j++)
dp[<<j][j] = Len[j]; for(int i = ; i<(<<n); i++)
for(int j = ; j<n; j++)
{
if(!(i&(<<j)) || dp[i][j]==INF) continue;
for(int k = ; k<n; k++)
if(!(i&(<<k)) && cost[j][k]!=INF)
dp[i|(<<k)][k] = min(dp[i|(<<k)][k], dp[i][j]+cost[j][k]);
} int ret = INF;
for(int i = ; i<n; i++)
ret = min(ret, dp[(<<n)-][i]);
return ret;
}
};
Trie ac; int dis[MAXN];
void BFS(int st)
{
queue<int> Q;
while(!Q.empty()) Q.pop();
for(int i = ; i<ac.L; i++)
dis[i] = INF;
dis[st] = ;
Q.push(st);
while(!Q.empty())
{
int u = Q.front(); Q.pop();
for(int i = ; i<ac.sz; i++)
{
int v = ac.next[u][i];
if(dis[v]==INF && !ac.end[v])
{
dis[v] = dis[u] + ;
Q.push(v);
}
}
}
for(int i = ; i<n; i++)
cost[Index[st]][i] = dis[pos[i]];
} char buf[MAXN];
int main()
{
while(scanf("%d%d",&n,&m)&&(n||m))
{
ac.init(,'');
memset(Index, -, sizeof(Index));
for(int i = ; i<n; i++)
{
scanf("%s", buf);
Len[i] = strlen(buf);
pos[i] = ac.insert(buf, false);
Index[pos[i]] = i;
}
for(int i = ; i<m; i++)
{
scanf("%s", buf);
ac.insert(buf, true);
}
ac.build();
for(int i = ; i<n; i++)
BFS(pos[i]); int ans = ac.query();
printf("%d\n", ans);
}
}

HDU3247 Resource Archiver —— AC自动机 + BFS最短路 + 状压DP的更多相关文章

  1. HDU3247 Resource Archiver (AC自动机+spfa+状压DP)

    Great! Your new software is almost finished! The only thing left to do is archiving all your n resou ...

  2. HDU 3247 Resource Archiver (AC自动机+BFS+状压DP)

    题意:给定 n 个文本串,m个病毒串,文本串重叠部分可以合并,但合并后不能含有病毒串,问所有文本串合并后最短多长. 析:先把所有的文本串和病毒都插入到AC自动机上,不过标记不一样,可以给病毒标记-1, ...

  3. hdu3247Resource Archiver (AC自动机+最短路+状压dp)

    Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others) Total Submis ...

  4. HDU 4568 Hunter 最短路+状压DP

    题意:给一个n*m的格子,格子中有一些数,如果是正整数则为到此格子的花费,如果为-1表示此格子不可到,现在给k个宝藏的地点(k<=13),求一个人从边界外一点进入整个棋盘,然后拿走所有能拿走的宝 ...

  5. 最短路+状压DP【洛谷P3489】 [POI2009]WIE-Hexer

    P3489 [POI2009]WIE-Hexer 大陆上有n个村庄,m条双向道路,p种怪物,k个铁匠,每个铁匠会居住在一个村庄里,你到了那个村庄后可以让他给你打造剑,每个铁匠打造的剑都可以对付一些特定 ...

  6. 【BZOJ1097】[POI2007]旅游景点atr 最短路+状压DP

    [BZOJ1097][POI2007]旅游景点atr Description FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺 ...

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

    题目链接:hdu_3247_Resource Archiver 题意: 有n个资源串,m个病毒串,现在要将所有的资源串整合到一个串内,并且这个串不能包括病毒串,问最短的串长为多少 题解: 将资源串和病 ...

  8. HDU - 3247 Resource Archiver (AC自动机,状压dp)

    \(\quad\)Great! Your new software is almost finished! The only thing left to do is archiving all you ...

  9. 【CodeVS2800】 送外卖 最短路+状压DP

    首先求出各点之间的最短路,floyed即可,注意是0-n. 然后考虑状压,f[i][j]表示状态为i时访问j点时的最短路和,1表示访问,0表示未访问,然后第j个点所在的位置就是(1<<j) ...

随机推荐

  1. 发送Post的请求代码

    通过浏览器访问的URL请求,都是GET请求,接下来代码是模拟POST发送请求 import java.io.BufferedReader; import java.io.FileNotFoundExc ...

  2. 【SQL】SQL Server中存储过程的调试方法

    1.以管理员用户登录DB服务器,把域用户追加到「Administrators」组. 2.在本机上以域用户登录,启动VS. 3.追加DB连接 4.右击要debug的存储过程,选择「ストアドプロシージャに ...

  3. ie下div模拟的表格,表头表体无法对齐

    现象:ie下,如果某个区域滚动显示表格内容(div模拟的table),表体出现滚动条的时候,会跟表头无法对齐. 解决方法:1.首先需要知道两个高度:表体最大高度height1.目前表体要显示的内容高度 ...

  4. 【Python】向函数传递任意数量的实参

    传递任意数量的实参 有时候,你预先不知道函数需要接受多少个实参,好在Python允许函数从调用语句中收集任意数量的实参 def get_letter(*letters): for i in lette ...

  5. mysql导出导入所有数据库

    导出所有数据库 mysqldump -uroot -p123456 --all-databases > /home/aa.sql 导入所有数据库 mysql -uroot -p123456 &l ...

  6. Session对象失效的客户端解决方法

    ASP(Active Server Pages)技术的Session对象用于存储用户在对话期间的私有信息.当前用户的Session对象中定义的变量和对象能在页面之间共享,但是不能为应用中其他用户所访问 ...

  7. cenos7 修改hostname

    hostnamectl set-hostname Linuxidc 如何在CentOS 7上修改主机名 在CentOS中,有三种定义的主机名:静态的(static),瞬态的(transient),和灵 ...

  8. HUAWEI HiAI亮相华为开发者生态大会 助力应用AI开发实现加速度

    6月23日,在2018华为终端·全球合作伙伴及开发者大会AI分论坛体验区的一角,被层层叠叠的人群围得水泄不通.站在最前面的一名体验者,正跟随着“快手短视频”APP上不断出现的小人左右扭动,每完成一个动 ...

  9. Double类parseDouble()和valueOf()方法的区别

    数字类型的String字符串转换为浮点数通常采用parseDouble()和valueOf()方法, 两者主要是存在以下两点区别. 区别一:参数区别Double.parseDouble(java.la ...

  10. Python学习笔记18:标准库之多进程(multiprocessing包)

    我们能够使用subprocess包来创建子进程.但这个包有两个非常大的局限性: 1) 我们总是让subprocess执行外部的程序,而不是执行一个Python脚本内部编写的函数. 2) 进程间仅仅通过 ...