hdu2222 ac自动机。。。。
来源:互联网 发布:手机指纹锁软件下载 编辑:程序博客网 时间:2024/05/21 16:59
http://acm.hdu.edu.cn/showproblem.php?pid=2222
题目链接在此~
说下题目大意 给出case数,多组数据,每组数据中有n个子串,给出目标串,求出共有多少个子串在目标串中出现过,输出数量。
一开始的思路是运用hash,枚举子串长度,计算hash值,相等则答案加一。。妥妥的tle。。。
附上代码求大牛优化。。。
(就算不tle也有可能wa。。。)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char word[11000][60];
char x[1100000];
typedef unsigned long long ll;
ll hash[1100000][60];
bool hashs[1100000][60]={false};
ll xp[1100000];
ll hash1[1100000][60];
int base=31;
int N;
int lens;
bool fail=false;
ll gethash(char * a,ll hashr[][60])
{
fail=false;
int len=strlen(a);
int i;
hashr[len][0]=0;
for(i=len-1;i>=0;i--)
{
if(a[i]<'a'&&a[i]>'z')
{
fail=true;
break;
}
hashr[i][0]=hashr[i+1][0]*base+a[i]-'a'+1;
}
return hashr[0][0];
}
int find_sub()
{
int i;
int ans=0;
for(i=0;i<N;i++)
{
ll temp=gethash(word[i],hash1);
if(fail)
return 0;
// cout<<temp<<endl;
int length=strlen(word[i]);
//cout<<lens<<endl;
int j;
for(j=0;j<=lens-length;j++)
{
if(!hashs[j][length])
{
//cout<<1<<endl;
hash[j][length]=hash[j][0]-hash[j+length][0]*xp[length];
hashs[j][length]=true;
}
//cout<<i<<" "<<j<<" "<<hash[j]-hash[j+length]*xp[length]<<endl;
if(temp==hash[j][length])
{ans++;break;}
}
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
xp[0]=1;
for(int i=1;i<1100000;i++)
{
xp[i]=xp[i-1]*base;
}
while(T--)
{
memset(hashs,0,sizeof(hashs));
scanf("%d",&N);
int i;
for(i=0;i<N;i++)
{
scanf("%s",word[i]);
}
scanf("%s",x);
lens=strlen(x);
gethash(x,hash);
if(fail)
return 0;
printf("%d\n",find_sub());
}
return 0;
}
咳咳。步入正题。
因为运用hash多次超时,然后发现这道题被作为了ac自动机的模板题。。
当看到这个名字的时候别提多激动了。。。有了这个还比什么acm啊。。。ac自动啊。。。
当我得知真相的那一刻。。。唉。
ac自动机有三步,构建trie树,bfs构建fail指针,最后进行目标串匹配。
个人任务构建fail指针最难没有之一。。毕竟kmp还运用不熟练呢。。。
参考大牛代码作出如下ac自动机。。。。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int kind=26;
struct node{
node * fail;
node * next[kind];
int count;
node()
{
memset(next,0,sizeof(next));
count=0;
fail=NULL;
}
}*q[510000];//队列
char word[60];//子串
char words[1100000];//目标串
int head,tail;
void insert(node* root,char *x)//trie树插入操作
{
int i=0,index;
node* p=root;
while(x[i])
{
index=x[i]-'a';
if(p->next[index]==NULL)
p->next[index]=new node();
p=p->next[index];
i++;
}
p->count++;
}
void build_fail(node* root)//构建指针
{
int i;
root->fail=NULL;
q[head++]=root;
while(head!=tail)//队列
{
node* temp=q[tail++];//出队
node*p=NULL;
for(i=0;i<26;i++)//遍历
{
if(temp->next[i]!=NULL)
{
if(temp==root)//root的子节点fail为root
{
temp->next[i]->fail=root;
}
else{
p=temp->fail;
while(p!=NULL)
{
if(p->next[i]!=NULL)
{
temp->next[i]->fail=p->next[i];
break;
}
p=p->fail;
}
if(p==NULL)
{
temp->next[i]->fail=root;
}
}
q[head++]=temp->next[i];//入队
}
}
}
}
int ac_auto(node* root)//匹配。。
{
int i=0,c=0,index;
node*p=root;
while(words[i])
{
index=words[i]-'a';
while(p->next[index]==NULL&&p!=root)//失配转向fail指针
p=p->fail;
p=p->next[index];
p=(p==NULL)?root:p;
node* temp=p;
while(temp!=root&&temp->count)//重复匹配过程
{
c+=temp->count;
temp->count=0;
temp=temp->fail;
}
i++;
}
return c;
}
int main()
{
int n,cases;
scanf("%d",&cases);
while(cases--)
{
head=tail=0;
node*root =new node();
scanf("%d",&n);
getchar();
while(n--)
{
gets(word);
//puts(word);
insert(root,word);
}
build_fail(root);
gets(words);
printf("%d\n",ac_auto(root));
}
return 0;
}
- hdu2222 ac自动机模版
- hdu2222 AC自动机
- hdu2222,(ac自动机)
- HDU2222-tire,AC自动机
- AC自动机模板 hdu2222
- hdu2222-AC自动机
- HDU2222 AC自动机
- hdu2222 AC自动机
- 【AC自动机】HDU2222
- hdu2222 AC自动机
- hdu2222 ac自动机。。。。
- HDU2222 AC自动机入门
- hdu2222 ac自动机模板
- hdu2222 AC自动机
- 初识AC自动机 HDU2222
- hdu2222(AC自动机入门)
- AC自动机 hdu2222
- HDU2222 AC自动机模板
- The main differences between Unmount , Eject and Safely Remove Drive
- CentOS 6中yum本地源的配置
- 笔记23--android AsyncTask
- 第九周 项目1--定义一目运算符-和Complex中的<< >>的重载
- GNU Make学习总结(一)
- hdu2222 ac自动机。。。。
- 日媒:阿里巴巴上市融资或超Facebook
- C#复制文件、设置隐藏,只读属性
- sqlserver换版本之后的操蛋事情备忘
- 编程杂项
- vxworks下的串口测试程序
- 办公系统的学习(手动调用在线人数减一;两个打开页面如何传值,等)
- 微软专利:使用者可以“隔空”操控手机和平板电脑
- Android幻灯片式图片浏览器