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][ ...
随机推荐
- 2014年辛星解读css第五节
本小节我们解说css中的"盒模型".即"box model",它通经常使用于在布局的时候使用,这个"盒模型"也有人成为"框模型&q ...
- 用live555做流媒体转发服务器?
当我们看到这里,说明大家都有这样的一个想法:那就是如何用live555实现一个直播代理转发的流媒体服务器? 我们先不着急去讨论用live555实现流媒体转发的技术方法123,先从live555的整个架 ...
- 如何分析一个已有的Delphi项目源代码
分析一个已有的Delphi项目,应该从以下入手(按先后顺序):1. 编译条件,包括自定义的Condition以及inc文件里的标识2. 主项目文件dpr,因为窗体的windows消息循环只是程序的一部 ...
- 3D数学读书笔记——向量运算及在c++上的实现
本系列文章由birdlove1987编写.转载请注明出处. 文章链接: http://blog.csdn.net/zhurui_idea/article/details/24782661 ...
- MVC设计模式应用
MVC登录程序清单 1 User JAVABean 用户登录操作类,跟数据库中表的信息对应 2 DatabaseConnection JavaBean 负责数据库的连接和关闭操作 3 IUserDAO ...
- Apache Thrift的简单介绍
1.什么是Thrift thrift是一种可伸缩的跨语言服务的发展软件框架.它结合了功能强大的软件堆栈的代码生成引擎,以建设服务.不同开发语言开发的服务可以通过该框架实现通信. thrift是face ...
- git多人协作冲突解决方法
http://www.trinea.cn/dev-tools/git-skill/ http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361 ...
- POJ2478 Farey Sequence —— 欧拉函数
题目链接:https://vjudge.net/problem/POJ-2478 Farey Sequence Time Limit: 1000MS Memory Limit: 65536K To ...
- CSU1553 Good subsequence —— 二分 + RMQ/线段树
题目链接: http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1553 Description Give you a sequence of n n ...
- poj 3617 Best Cow Line 解题报告
题目链接:http://poj.org/problem?id=3617 题目意思:给出一条长度为n的字符串S,目标是要构造一条字典序尽量小,长度为n的字符串T.构造的规则是,如果S的头部的字母 < ...