zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    十一月计划
    归并排序+例题
    今年暑假不AC(简单贪心)
    路障(BFS)
    堆优化版Dijkstra模板
    十月计划
    Find a way(BFS)
    Prime Path(BFS)
    Find The Multiple
    k8s中node节点资源不足
  • 原文地址:https://www.cnblogs.com/trav/p/10483951.html
Copyright © 2011-2022 走看看