[uva] 1671 History of Languages

题目描述

输入两个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;
}

原文地址:https://www.cnblogs.com/trav/p/10483951.html

时间: 2024-10-24 04:50:30

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

uva 111 History Grading(DP初步应用)

uva 111 History Grading Many problems in Computer Science involve maximizing some measure according to constraints. Consider a history exam in which students are asked to put several historical events into chronological order. Students who order all

uva 101 History Grading

Background Many problems in Computer Science involve maximizing some measure according to constraints. Consider a history exam in which students are asked to put several historical events into chronological order. Students who order all the events co

UVA 111 History Grading (最长公共子序列)

History Grading Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Background Many problems in Computer Science involve maximizing some measure according to constraints. Consider a history exam in which students are asked to put s

Uva 10336 Rank the Languages

1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 void Dfs(int x,int y); 5 char MapString[1000][1000]={0};//要判断的“地图” 6 bool vis[1000][1000]={0};//节点是否本访问过, 7 int main() 8 { 9 int h,w;//h:height;w:width 10 int line; 11 int MaxCh

UVA 10887 Concatenation of Languages 字符串hash

题目链接:https://vjudge.net/problem/UVA-10887 题意: 给你两个集合A,B,任意组合成新的集合C(去重) 问你最后C集合大小 题解: 暴力 组成的新串hash起来 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1

uva 111 - History Grading (dp, LCS)

题目链接 题意:给N,第二行是答案,n个数c1---cn, 代表第一个的顺序是c1,第二个数顺序是c2; 下面每一行是学生的答案,格式同上. 注意:这个给的顺序需要处理一下,不能直接用. 思路:LCS. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 using namespac

UVa 111 - History Grading

题目:历史上有一些事件发生的先后顺序,现在有很多学生写了不同的顺序表, 判断每个学生的最大的前后顺序正确的序列. 分析:dp,LIS,最大上升子序列. 注意本题的数据格式,串里的每个元素对应于:对应下标编号的事件在表中的位置: 状态:F(n)记录以第n个元素为结束元素的序列的最长上升子序列,有转移方程: F(n)= max(F(i)+1)  { 其中 0 < i < n 且 data[i] < data[n] }. 说明:发现好多dp题(⊙_⊙). #include <iostre

UVA 111 History Grading 【lcs】

Brief Description: 一个历史考试,有n个历史事件, 它们之间的年份是不同的,要学生把这些事件按照正确的顺序排列出来.有两种记分方式,采用的是第二种: 假设有历史事件1,2,3,4, 它们正确的时间顺序是1,2,3,4, 然后假设学生的答案是1,3,2,4, 那么按照相对顺序正确的数量,答对了三个(1,2,4或者1,3,4),也就是它与正确答案的最长公共子序列长度是3,便是答对的数量. Analyse: 最长公共子序列模板题,但是这题的输入是个很大的坑,他的输入是按照顺序,事件1

ACM总结——dp专辑(转)

感谢博主——      http://blog.csdn.net/cc_again?viewmode=list       ----------  Accagain  2014年5月15日 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间效率高,代码量少,多元性强,主要考察思维能力.建模抽象能力.灵活度. 本人动态规划博客地址:http://blog.csdn.net/cc_again/article/category/1261899 ***********************