题目描述

输入两个DFA,判断是否等价。

https://uva.onlinejudge.org/external/16/1671.pdf

输入

第一行T 可以接受的字母表

第二行N 状态数

接下去N行 每个状态的情况 第一个表示是否为接受状态 后面T个是接受字母i可以转移到的状态 -1表示不转移

输出

等价输出Yes,不等价输出No

样例输入

2

3

1 -1 1

0 -1 2

0 -1 0

2

1 -1 1

0 -1 0

3

4

1 -1 -1 1

1 -1 -1 2

1 -1 -1 3

1 -1 -1 1

2

1 -1 -1 1

1 -1 -1 0

0

样例输出

Case #1: No

Case #2: Yes

思路

参考刘神的思路,求DFA2的补,然后与DFA1测试相交。如果不相交,当然是等价。

求补的思路就是把接受状态全都取反。求相交的思路就是BFS,或者DFS。我用的是BFS,很快,复杂度O(n)。

一个重要的细节,我在这上面卡了很久,就是怎么处理-1的情况。最后的解法是设一个孤岛结点,孤岛的所有转移都指向自己,-1的情况就转移到孤岛,孤岛自己不是接受状态。这样做的正确性:原DFA可以接受的状态集没有改变。因为我只需要知道那些输入可以接受,其余的就是不接受的输入。

但是如果不要孤岛,怎么直接处理-1的情况?

首先,如果遇到-1直接pass,那么处理不了

DFA1: 1->2->3->4->5(ac)

DFA2: 1->2->3->4->5(ac)->6(ac)

或者

DFA2: 1->2->3->4->5(ac)->6->7-> ... ->n(ac)

而且,处理起来很麻烦,情况很多,所以还是加个孤岛结点吧。

实现

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std; const int maxn = 2010; // size of state
const int maxm = 30; // size of alphabet int T; // T <= 26
int n1, n2; // n <= 2000
bool is_final1[maxn], is_final2[maxn];
int dfa1[maxn][maxm], dfa2[maxn][maxm]; bool init()
{
scanf("%d", &T);
if (T == 0)
return false; scanf("%d", &n1);
for (int i = 0; i < n1; i++) {
int f1;
scanf("%d", &f1);
is_final1[i] = ((f1 == 1) ? true : false);
for (int j = 0; j < T; j++) {
scanf("%d", &dfa1[i][j]);
dfa1[n1][j] = n1;
if (dfa1[i][j] == -1) // 孤岛状态
dfa1[i][j] = n1;
}
}
is_final1[n1] = 0; // 孤岛 scanf("%d", &n2);
for (int i = 0; i < n2; i++) {
int f2;
scanf("%d", &f2);
is_final2[i] = ((f2 == 1) ? true : false);
for (int j = 0; j < T; j++) {
scanf("%d", &dfa2[i][j]);
dfa2[n2][j] = n2;
if (dfa2[i][j] == -1) // 孤岛状态
dfa2[i][j] = n2;
}
}
is_final2[n2] = 0;
return true;
} bool visit[maxn][maxn];
bool bfs(int a1[maxn][maxm], int a2[maxn][maxm], bool b1[maxn], bool b2[maxn])
{
memset(visit, false, sizeof visit);
queue<pair<int,int> > Q; Q.push(make_pair(0, 0));
visit[0][0] = true; while (!Q.empty()) {
pair<int,int> P = Q.front();
Q.pop();
if (b1[P.first] && !b2[P.second]) // 2求补集
return true; // 发现相交 for (int i = 0; i < T; i++) {
// bfs 遍历未访问转移状态
if (visit[a1[P.first][i]][a2[P.second][i]] == false) {
visit[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 kase = 0;
while (init()) {
printf("Case #%d: ", ++kase);
if (!bfs(dfa1, dfa2, is_final1, is_final2)
&& !bfs(dfa2, dfa1, is_final2, is_final1))
printf("Yes\n");
else
printf("No\n");
}
return 0;
}

[uva] 1671 History of Languages的更多相关文章

  1. UVa 111 - History Grading (by 最长公共子序列 )

     History Grading  Background Many problems in Computer Science involve maximizing some measure accor ...

  2. uva 111 History Grading(最长公共子序列)

    题目连接:111 - History Grading 题目大意:给出一个n 代表序列中元素的个数, 然后是一个答案, 接下来是若干个同学的答案(直到文件结束为止), 求出两个序列的最长公共子序列, 注 ...

  3. UVA, 10336 Rank the Languages

    难点在于:递归函数和输出: #include <iostream> #include <vector> #include <algorithm> #include ...

  4. UVA 111 History Grading

    读题读了好久,其实就是在输入数据时要对数据的位置进行相应的改变 #include<iostream> #include<cstring> #include<cstdio& ...

  5. uva 111 - History Grading (dp, LCS)

    题目链接 题意:给N,第二行是答案,n个数c1---cn, 代表第一个的顺序是c1,第二个数顺序是c2; 下面每一行是学生的答案,格式同上. 注意:这个给的顺序需要处理一下,不能直接用. 思路:LCS ...

  6. UVa 111 History Grading (简单DP,LIS或LCS)

    题意:题意就是坑,看不大懂么,结果就做不对,如果看懂了就so easy了,给定n个事件,注意的是, 它给的是第i个事件发生在第多少位,并不是像我们想的,第i位是哪个事件,举个例子吧,4 2 3 1, ...

  7. uva 111 History Grading(lcs)

    题目描述 在信息科学中有一些是关于在某些条件限制下,找出一些计算的最大值. 以历史考试来说好了,学生被要求对一些历史事件根据其发生的年代顺序来排列.所有事件顺序都正确的学生无疑的可以得满分.但是那些没 ...

  8. UVA 10887 Concatenation of Languages 字符串hash

    题目链接:传送门 题意: 给你两个集合A,B,任意组合成新的集合C(去重) 问你最后C集合大小 题解: 暴力 组成的新串hash起来 #include<bits/stdc++.h> usi ...

  9. UVa 1671 语言的历史——判断两个DFA是否等价

    题意 一个DFA可以用一个5元组  $((Q, \sum , \delta , q_0, F))$ 表示,其中 $Q$ 为状态集,$\sum$ 为字母表,$\delta$ 为转移函数,$q_0$ 为起 ...

随机推荐

  1. openfire消息发送

    找了一些demo,做了一些示例,演示了基于xmpp协议的openfire的客户端之间消息的发送. 代码需要两个包,smack.jar ,smackx.jar. 第一个代码,只是点对点发送消息的,不涉及 ...

  2. 跨终端Web

    1.终端vs设备 H5页面运行在同一设备的不同终端下. (1)Web浏览器. (2)微信.QQ浏览器. (3)移动App的Webview. (4)TV机顶盒. 2.跨终端的实现方式 (1)响应式 存在 ...

  3. SpringBoot相知

    前言 这篇文章的将介绍表单验证,AOP处理请求和统一异常处理,案例是延续上一篇 SpringBoot初识 表单验证 现在将要拦截未满18岁的女生,在之前GirlController里面添加一个女生的方 ...

  4. Android的四大组件学习

    一.Linearlayout  :  线性布局 1. android:orientation="vertical"     //控件的方向控制,vertical : 垂直布局 ,  ...

  5. if判断和switch case 和三元运算符整理

    if判断和switch case 和三元运算符整理 例子1:if判断写法: <script type="text/javascript"> var num = 12; ...

  6. 《Python绝技:运用Python成为顶级黑客》 用Python进行无线网络攻击

    本章大部分代码都是实现了但是缺乏相应的应用环境,想具体测试的可以直接找到对应的环境或者自行修改脚本以适应生活常用的环境. 1.搭建无线网络攻击环境: 用Scapy测试无线网卡的嗅探功能: 插入无线网卡 ...

  7. 队列(链式队列)----C语言

    链式队列----用链表实现,链式队列就是一个操作受限的单向链表,如果读者了解单向链表的建立过程,那理解链式队列就很容易了,先回顾一下单向链表的建立过程 (不熟悉单向链表的可以先看看另一片随笔,再回来看 ...

  8. ZZNU 1719(最长上升子序列+最长下降子序列)

    先吐血一发,噗! 再吐血一次,啊啊啊啊! 好吧,做了那么多次最长上升子序列,看这题看了半天才发现还有最长下降子序列,呵呵哒! AC代码: #include<stdio.h>//老恶心#in ...

  9. POST 400 (BAD REQUEST)

    遇到这种错,1,F12打开控制台,2,点击network,找到发送的请求. 3,点击请求,4,看右侧的 Header Preview Response 应该能找到原因. 就拿刚才来说,找了好几个小时原 ...

  10. 《JAVA与模式》之原型模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述原型(Prototype)模式的: 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办 ...