[uva] 1671 History of Languages

Posted trav

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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
");
        else
            printf("No
");
    }
    return 0;
}

以上是关于[uva] 1671 History of Languages的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1671[Usaco2005 Dec]Knights of Ni 骑士 BFS

Leetcode 1671. Minimum Number of Removals to Make Mountain Array

Leetcode 1671. Minimum Number of Removals to Make Mountain Array

uva10305

UVA 111 History Grading

History of the Great Game