http://acm.hdu.edu.cn/showproblem.php?pid=2471
一道BFS的题 而不是自动机,算了不吐槽了...刘汝佳居然放在紫书的自动机章节第一题...Orz
题意就是给你了自动机两枚,判断他两是否是一样的。
判断方法:
1.剪掉死循环
保留可以到达AC态的状态和边。
我们知道自动机会有个AC态,那么对于到达不了AC态的死循环,我们可以把那些状态和那些边(转移函数)减掉。
判断一些状态和一些边(转移函数)能否到达AC态,只要从AC态开始,沿着反向边BFS全部节点。
这里我用了一个Cut函数进行预处理
2.检查两个自动机的每个状态
两个小叽叽,每个有n个状态,两两组合起来就有n*n个状态,n<=2000,所以n^2的复杂度还是可以接受的。
接下来从(0,0)开始BFS,判断可达的每个状态是否都一致,就看两个小叽叽是不是同为AC态或者中间态,还有看是否有一样的边(转移函数)出去。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MaxN=2011, MaxM=27;
#define mp make_pair<int,int>
#define pii pair<int,int>
bool vis[MaxN][MaxN];
int t,n1,n2;
struct Node{
int next[MaxM];
int ac;
}dfa1[MaxN], dfa2[MaxN];
bool can[MaxN];
int cas=1,f[MaxN][MaxM],head[MaxN],nex[MaxN*MaxM],cnt,v[MaxN*MaxM];
void Cut(Node *dfa,int *n){
queue<int>q;
cnt=0;
memset(can,0,sizeof can);
memset(head,-1,sizeof head);
for(int i=0;i<*n;i++){
if(dfa[i].ac)q.push(i),can[i]=1;
for(int j=0;j<t;j++){
if(dfa[i].next[j]==-1)continue;
nex[cnt]=head[dfa[i].next[j]];
v[cnt]=i;
head[dfa[i].next[j]]=cnt++;
}
}
while(!q.empty()){
int i;
for(i=head[q.front()],q.pop(); i!=-1;i=nex[i]){
if(!can[v[i]]){
can[v[i]]=1;
q.push(v[i]);
}
}
}
for(int i=0;i<*n;i++)
for(int j=0;j<t;j++){
if(dfa[i].next[j]!=-1 && !can[dfa[i].next[j]])
dfa[i].next[j]=-1;
}
}
void ReadData(Node *dfa,int *n){
scanf("%d",n);
for(int i=0;i<*n;i++){
scanf("%d",&dfa[i].ac);
for(int j=0;j<t;j++)
scanf("%d",&dfa[i].next[j]);
}
Cut(dfa,n);
}
bool BFS(){
queue<pii>q;
memset(vis,0,sizeof vis);
q.push(mp(0,0));
vis[0][0]=1;
while(!q.empty()){
pii cur=q.front();q.pop();
if(dfa1[cur.first].ac != dfa2[cur.second].ac) return false;
for(int i=0;i<t;i++){
int nex1=dfa1[cur.first].next[i],nex2=dfa2[cur.second].next[i];
if(!!(nex1+1) != !!(nex2+1))return false;
if(nex1==-1)continue;
if(!vis[nex1][nex2]){
vis[nex1][nex2]=1;
q.push(mp(nex1,nex2));
}
}
}
return true;
}
int main()
{
// freopen("data.in","r",stdin);
while(scanf("%d", &t)!=EOF && t){
ReadData(dfa1,&n1);
ReadData(dfa2,&n2);
printf("Case #%d: %s\n",cas++,BFS()?"Yes":"No");
}
return 0;
}