hdu 3247(ac自动机+状态压缩dp+最短路)
来源:互联网 发布:狸窝ppt转换器 mac 编辑:程序博客网 时间:2024/04/28 17:54
题意:有n个源文件也就是n个字符串(n<=10 长度<=1000),m种病毒也同样是m个字符串(m<=1000,总长度50000),现在要问最短的串包含所有源文件但不存在一个子串是病毒的长度,源文件的串可以重叠存在,所有字符串由01组成。
题解:好题,思路来自这里http://m.blog.csdn.net/blog/woshi250hua/8021283
问题可以转化为找出一个最短的串,包含所有源文件字符串且每个字符串可重叠出现仅一次,但不包含任何一个病毒字符串。因为源文件字符串最多10个,可以用状态压缩,每个位0表示没有出现,1表示出现。先把两种模式串都存到trie图中,val[i]表示存节点i的对应源文件状态,如果是病毒存成-1。f[s][i]是状态是s添加第i个源文件字符串的情况下最短串长度,状态转移f[s | val[flag[k]]][k] = min(f[s | val[flag[k]]][k], f[s][j] + dis[j][k])。这里flag[k]存第k个源文件节点编号,dis[j][k]是从第j个源文件跳转到第k个源文件的最小步数,用求最短路的方式求得。为什么是这个跳转的最小步数,是因为在trie图中,假如当前节点是i,它的fail指针指向的另一个节点j,那么从根节点到节点j的这个前缀串一定是根节点到节点i的一个后缀串,且一定是最长后缀,所以dis[j][k]这条路径是从根节点开始,先走到节点flag[j],完成了源文件flag[j]串,最后通过fail指针走到节点flag[k],整条路径刚好是包含了两个重叠的源文件串,自己画图能更好理解。所以预处理出所有节点到其他节点的”最短路”就能优化求最短长度符合要求的串。最后在f[(1 << n) - 1][i]中找最小值就是解。
#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;const int N = 60005;const int INF = 0x3f3f3f3f;int Next[N][2], val[N], fail[N], sz, n, m;int flag[11], f[1030][11], cnt, d[N], vis[N], mindis[11][11];char str[N];void init() { memset(Next[0], 0, sizeof(Next[0])); val[0] = 0; sz = 1;}void insert(char *s, int v) { int u = 0, len = strlen(s); for (int i = 0; i < len; i++) { int k = s[i] - '0'; if (!Next[u][k]) { memset(Next[sz], 0, sizeof(Next[sz])); val[sz] = 0; Next[u][k] = sz++; } u = Next[u][k]; } val[u] = v;}void getFail() { queue<int> Q; fail[0] = 0; for (int i = 0; i < 2; i++) if (Next[0][i]) { fail[Next[0][i]] = 0; Q.push(Next[0][i]); } while (!Q.empty()) { int u = Q.front(); Q.pop(); if (val[fail[u]] == -1) val[u] = -1; else val[u] |= val[fail[u]]; for (int i = 0; i < 2; i++) { if (!Next[u][i]) Next[u][i] = Next[fail[u]][i]; else { fail[Next[u][i]] = Next[fail[u]][i]; Q.push(Next[u][i]); } } }}void spfa(int s) { queue<int> Q; memset(d, INF, sizeof(d)); memset(vis, 0, sizeof(vis)); d[s] = 0; vis[s] = 1; Q.push(s); while (!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = 0; for (int i = 0; i < 2; i++) { if (d[Next[u][i]] > d[u] + 1 && val[Next[u][i]] >= 0) { d[Next[u][i]] = d[u] + 1; if (!vis[Next[u][i]]) { Q.push(Next[u][i]); vis[Next[u][i]] = 1; } } } }}int solve() { flag[0] = 0; cnt = 1; for (int i = 0; i < sz; i++) if (val[i] > 0) flag[cnt++] = i; for (int i = 0; i < cnt; i++) { spfa(flag[i]); for (int j = 0; j < cnt; j++) mindis[i][j] = d[flag[j]]; } int all = 1 << n; memset(f, INF, sizeof(f)); f[0][0] = 0; for (int i = 0; i < all; i++) for (int j = 0; j < cnt; j++) if (f[i][j] < INF) { for (int k = 0; k < cnt; k++) { if (mindis[j][k] == INF || j == k) continue; f[i | val[flag[k]]][k] = min(f[i | val[flag[k]]][k], f[i][j] + mindis[j][k]); } } int res = INF; for (int i = 0; i < cnt; i++) res = min(res, f[all - 1][i]); return res;}int main() { while (scanf("%d%d", &n, &m) == 2 && n + m) { init(); for (int i = 0; i < n; i++) { scanf("%s", str); insert(str, 1 << i); } for (int i = 0; i < m; i++) { scanf("%s", str); insert(str, -1); } getFail(); printf("%d\n", solve()); } return 0;}
- hdu 3247(ac自动机+状态压缩dp+最短路)
- AC自动机+状态压缩dp+BFS求最短路+hdu3247
- HDU 3247 AC自动机 + 状态压缩dp
- HDU 4534(ac自动机+状态压缩dp)
- hdu 2825 ac自动机+状态压缩dp
- hdu 4057 AC自动机+状态压缩dp
- hdu 2825(ac自动机+状态压缩dp)
- hdu 2858 ac自动机 +状态压缩dp
- HDU 3247 Resource Archiver[AC自动机+最短路+dp]
- HDU 3247 ac自动机+bfs+状态压缩dp
- hdu 2825 Wireless Password AC自动机+状态压缩DP
- HDU 2825 Wireless Password(AC自动机+状态压缩DP)
- HDU 2825 Wireless Password AC自动机 + 状态压缩DP
- HDU 2825 Wireless Password (AC自动机 + 状态压缩DP)
- hdu 2825 Wireless Password (ac自动机+状态压缩dp)
- HDU 2825 Wireless Password (AC自动机+DP+状态压缩)
- [HDU 2825] Wireless Password (AC自动机+状态压缩DP)
- HDU 2825 Wireless Password(AC自动机+状态压缩DP)
- 使用 Spring 3 来创建 RESTful Web Services
- OC单例宏写法
- RESTful WebService入门
- Delaunay三角剖分
- 如何使用Git上传项目代码到github
- hdu 3247(ac自动机+状态压缩dp+最短路)
- mongodb安装初步
- Android getDimensionPixelSize, 代码中设置字体大小,读xml配置。
- vc 网络连接的测试方法
- oracle按时间段查询
- MATLAB中的分类器
- iOS 被键盘遮挡时,带有textfield的tableview自动上移
- 请问两个div之间的上下距离怎么设置
- 抓取网页信息并获取生成xml文件(以网页彩票数据为例)