原题:https://uva.onlinejudge.org/external/16/1671.pdf
题意简述:给两个DFA,判断是否等价。
Key:1. 两个DFA等价 iff 任一个的补与另一个交为空;
2. 补集即反转终态与非终态,交集用bfs。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 2000, maxd = 30;
int T, n1, n2, dfa1[maxn][maxd], dfa2[maxn][maxd]; //字母表大小,状态数,转移函数
bool isFinal1[maxn], isFinal2[maxn]; //是否终态
bool init ()
{
scanf("%d", &T);
if (T==0) return false;
scanf("%d", &n1);
for (int i=0; i<n1; ++i)
{
int t;
scanf("%d", &t);
isFinal1[i] = t;
for (int j=0; j<T; ++j)
{
scanf("%d", &dfa1[i][j]);
}
}
scanf("%d", &n2);
for (int i=0; i<n2; ++i)
{
int t;
scanf("%d", &t);
isFinal2[i] = t;
for (int j=0; j<T; ++j)
{
scanf("%d", &dfa2[i][j]);
}
}
return true;
}
bool vis[maxn][maxn];
bool bfs (int i1, int i2, int a1[maxn][maxd], int a2[maxn][maxd], bool *b1, bool *b2) // 1取补,2不取
{
memset(vis, false, sizeof(vis));
queue<pair<int, int>> Q;
Q.push(make_pair(0,0));
vis[0][0] = true;
while (!Q.empty())
{
pair<int, int> p = Q.front();
Q.pop();
if (!b1[p.first] && b2[p.second]) return true;
for (int i=0; i<T; ++i)
{
if (a1[p.first][i]!=-1 && a2[p.second][i]!=-1 && !vis[a1[p.first][i]][a2[p.second][i]])
{
vis[a1[p.first][i]][a2[p.second][i]] = true;
Q.push(make_pair(a1[p.first][i], a2[p.second][i]));
}
}
}
return false;
}
int main ()
{
int cas = 1;
while (init())
{
printf("Case #%d: ",cas++);
if (!bfs(n1,n2,dfa1,dfa2,isFinal1,isFinal2) && !bfs(n2,n1,dfa2,dfa1,isFinal2,isFinal1))
{
printf("Yes\n");
}
else printf("No\n");
}
return 0;
}