POJ1699【AC自动机+状压DP_感言】
萌新感言:
我的天呐!
因为是AC自动机的专题所以没有管别的。。。硬着头皮吃那份题解(代码)。。【请戳简单美丽可爱的代码(没开玩笑)】
首先讲AC自动机:
tag存的是以这个节点为后缀的字符串个数(已状压)。
我们在构造fail指针的时候,采用的是BFS的手段,对于树而言,那就是一层一层的向下遍历,
所以代码很巧妙(不能说巧妙吧,就是这样的),在找到fail位置的时候直接跳出,然后更新了tag,为什么可以这样?因为长的找到的时候,短的早就找过了,所以直接更新就好了。
然后这份代码有一个小瑕疵(讲错请吐槽!):因为在构造fail指针的时候tag已经更新过了,所以在DP的时候没必要再找到fail指针然后更新。
自身问题(可跳过):
还有构造fail的函数中当节点不存在的时候,这个节点的位置,用父节点的这个元素的fail指针取代了,如图:
道理还是一样,我要保证长的找到的时候,短的早就找过了。
然后讲DP:
感觉AC自动机下的DP很好理解,因为Trie树上本身对于每个节点就是一种种状态,用BFS的手段从上层到下层遍历。
DP[ i ][ j ]表示匹配到 i 节点,匹配到 j 个字符串时的最短步数。
每次只会伸展一个新节点,从而获取更多的后缀串,所以
dp[x][new_string_num]=min(dp[x][new_string_num],dp[x的父节点][old_string_num]+1);
that's all,thanks for watching....
//#include <bits/stdc++.h>
#include<iostream>
#include<queue>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N=205;
const int INF=0x3f3f3f3f;
int n,dp[N][1030];
int g[N][4],fail[N],tag[N];
int sz; void init()
{
sz=1;
tag[0]=0;
memset(g[0],0,sizeof(g[0]));
} int GetID(char x)
{
if(x=='A') return 0;
if(x=='T') return 1;
if(x=='C') return 2;
return 3;
} void INS(char *str,int id)
{
int len=strlen(str),index,root=0;
for(int i=0;i<len;i++){
index=GetID(str[i]);
if(g[root][index]==0)
{
tag[sz]=0;
memset(g[sz],0,sizeof(g[sz]));
g[root][index]=sz++;
}
root=g[root][index];
}
tag[root]|=(1<<id);
} void Build_fail()
{
queue<int>que;
for(int i=0;i<4;i++)
{
int u=g[0][i];
if(u){
fail[u]=0;
que.push(u);
}
} while(!que.empty())
{
int root=que.front();
que.pop();
for(int i=0;i<4;i++){
int u=g[root][i];
if(!u){
g[root][i]=g[fail[root]][i];//如果这个节点不存在 用父节点的这个元素的fail指针取代了
continue;
}
que.push(u);
int v=fail[root];
while(v && g[v][i]==0)
v=fail[v];
fail[u]=g[v][i]; //构造
tag[u]|=tag[fail[u]]; //更新节点存的字符串个数。
}
}
} int solve()
{
//初始化
Build_fail();
memset(dp,INF,sizeof(dp));
dp[0][0]=0;
queue<PII>que;
que.push(make_pair(0,0));//塞入根节点,匹配0; while(!que.empty())
{
int u=que.front().first;
int s=que.front().second;
que.pop(); for(int i=0;i<4;i++){
int k=g[u][i]; //匹配这个节点,因为之前当节点不存在的时候已经存了父节点的该元素的fail指针,所以不用考虑为空
int ss=s|tag[k]; //在建立fail指针的时候,tag[k]存的字符串个数已经更新
if(dp[k][ss]>dp[u][s]+1)
{
dp[k][ss]=dp[u][s]+1;
que.push(make_pair(k,ss));
if(ss==(1<<n)-1)
return dp[k][ss];
}
}
}
return 0;
} int main()
{
int T;
char s[30];
scanf("%d",&T);
while(T--){
init();
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",s);
INS(s,i);
}
printf("%d\n",solve());
}
return 0;
}
POJ1699【AC自动机+状压DP_感言】的更多相关文章
- hdu 2825 aC自动机+状压dp
Wireless Password Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- hdu 6086 -- Rikka with String(AC自动机 + 状压DP)
题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...
- [BZOJ1559]密码 AC自动机+状压
问题 K: [JSOI2009]密码 时间限制: 1 Sec 内存限制: 64 MB 题目描述 众所周知,密码在信息领域起到了不可估量的作用.对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝 ...
- bzoj 1212: [HNOI2004]L语言 AC自动机+状压
为什么这道题网上所有题解写的都是N*Len的trie树的暴力啊,4E的复杂度... 为什么暴力还跑这么快啊TAT.. 有一个O(Len)的做法就是先把AC自动机建出来,因为每个字典串的长度很小,所以我 ...
- [HNOI2006]最短母串问题——AC自动机+状压+bfs环形处理
Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 32MB Input 第一行是一个正整数n(n< ...
- BZOJ1559 [JSOI2009]密码 【AC自动机 + 状压dp】
题目链接 BZOJ1559 题解 考虑到这是一个包含子串的问题,而且子串非常少,我们考虑\(AC\)自动机上的状压\(dp\) 设\(f[i][j][s]\)表示长度为\(i\)的串,匹配到了\(AC ...
- UVALive - 4126 Password Suspects (AC自动机+状压dp)
给你m个字符串,让你构造一个字符串,包含所有的m个子串,问有多少种构造方法.如果答案不超过42,则按字典序输出所有可行解. 由于m很小,所以可以考虑状压. 首先对全部m个子串构造出AC自动机,每个节点 ...
- [HNOI2006]最短母串 (AC自动机+状压)
Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12) ...
- HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解
题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...
随机推荐
- 如何使Htm页面使用IE9文档模式
修改Htm页面的方法之一是,在Head->Title下添加<META http-equiv="X-UA-Compatible" content="IE=9&q ...
- RNN 的入门程序DEMO
1.视频介绍 https://www.youtube.com/watch?v=cdLUzrjnlr4 2. https://github.com/llSourcell/recurrent_neural ...
- AndroidPageObjectTest_Chained.java
以下代码使用ApiDemos-debug.apk进行测试 //这个脚本用于演示PageFactory的功能:链式注解@AndroidFindBys.@IOSFindBys.具体用法参考页面类的代码. ...
- java.lang.ClassNotFoundException: Didn't find class "org.reactivestreams.Publisher" on path
缺少jar包 reactive-streams-1.0.0.jar 和 reactive-streams-1.0.0-sources.jar 常用于 Rxjava 开发过程中 <?xml ...
- ThinkPHP验证码不现实的处理方法
ThinkPHP测试的时候遇到验证码不显示的问题,主要解决思路如下: 1.php.ini是否开启gd库: 2.页面编码是否一致: 3.检查页面头部信息BOM,这是最主要的,把下面代码复制到根目录下,然 ...
- HTTP1.0 与HTTP2.0的区别
一.多路复用 HTTP2.0 使用了多路复用技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级. 二.数据压缩 HTTP1.1不支持header数据压缩,HTTP ...
- HDU2586 How far away? —— 倍增LCA
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 How far away ? Time Limit: 2000/1000 MS (Java/Ot ...
- 从数据的角度带你深入了解IPFS
IPFS 和区块链有着非常紧密的联系, 随着区块链的不断发展,对数据的存储需求也越来越高.本文从IPFS 的底层设计出发, 结合源代码, 分析了IPFS 的一些技术细节. 一.概述 IPFS 和区块链 ...
- avf_showspectrum.c:112: undefined reference to `av_rdft_end
下面还有一堆错,是由于ffmpeg库没编好,重新编好即可
- 使用WebBrowser自动登录阿里妈妈网站
窗体上放一个WebBrowser,其Url属性设置为http://www.alimama.com/membersvc/member/login.htm,其他属性为默认 再放一个Button,默认 Bu ...