zoukankan      html  css  js  c++  java
  • HDU2471_History of Languages

    有意思的题目,给出两个自动机,判断这个两个自动机是否是等价的?

    两个自动机是等价的,那么他们可接受的字符串集合一定是完全一样的。

    于是我们可以从(0,0)开始bfs,每次看看在两个自动机上走到的两个点儿子指针以及终态信息是否完全一致,是的话就把所有儿子指针都拉到队列中进行后面的判断。

    由于我们对于每一个二元组,最多只需要判断一次,显然时间复杂度就不会超过n^2了。

    不过我个人觉得题目好像有些问题,在题目给出的数据中,自动机可能存在一些“不合法”的状态,什么意思呢?就是说有的状态,在它的所有后继状态中没有任何一个可以到达终态,但是这种状态在构建自动机的时候应该不会被构造出来吧?题目此处让我很疑惑。

    因此,我们需要从每一个终态开始沿着指针的反方向往回遍历一遍,看看那些状态是有用状态,然后bfs的时候只需要考虑有效的状态就好了。

    召唤代码君:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #define maxn 2020
    #define pr pair<int,int>
    #define mp(x,y) make_pair(x,y)
    using namespace std;
    
    int next[2][maxn][26],tag[2][maxn];
    int n[2],m;
    bool vis[2][maxn],walk[2][maxn],f[maxn][maxn];
    vector<int> from[2][maxn];
    
    void _init(int x)
    {
        for (int i=0; i<n[x]; i++){
            vis[x][i]=false;
            walk[x][i]=false;
            from[x][i].clear();
        }
        if (x==1){
            for (int i=0; i<n[0]; i++)
                for (int j=0; j<n[1]; j++) f[i][j]=false;
        }
    }
    
    void visit(int x,int cur)
    {
        if (vis[x][cur]) return ;
        vis[x][cur]=true;
        for (unsigned i=0; i<from[x][cur].size(); i++)
            visit(x,from[x][cur][i]);
    }
    
    bool match(int u,int v)
    {
        if (tag[0][u]!=tag[1][v]) return false;
        for (int i=0; i<m; i++)
            if ((next[0][u][i]>=0 && vis[0][next[0][u][i]])^(next[1][v][i]>=0 && vis[1][next[1][v][i]])) return false;
        return true;
    }
    
    bool check()
    {
        queue<pr> Q;
        Q.push(mp(0,0));
        while (!Q.empty()){
            int u=Q.front().first,v=Q.front().second;
            Q.pop();
            f[u][v]=true;
            if (!match(u,v)) return false;
            for (int i=0; i<m; i++){
                if (next[0][u][i]>0 && vis[0][next[0][u][i]]){
                    if (f[next[0][u][i]][next[1][v][i]]) continue;
                    Q.push(mp(next[0][u][i],next[1][v][i]));
                }
            }
        }
        return true;
    }
    
    int main()
    {
        int cas=0;
        while (scanf("%d",&m) && m){
            for (int i=0; i<2; i++){
                scanf("%d",&n[i]);
                _init(i);
                for (int j=0; j<n[i]; j++){
                    scanf("%d",&tag[i][j]);
                    for (int k=0; k<m; k++){
                        scanf("%d",&next[i][j][k]);
                        if (next[i][j][k]>=0) from[i][next[i][j][k]].push_back(j);
                    }
                }
                for (int j=0; j<n[i]; j++)
                    if (tag[i][j] && !vis[i][j]) visit(i,j);
            }
            printf("Case #%d: ",++cas);
            if (check()) puts("Yes");
                else puts("No");
        }
        return 0;
    }
  • 相关阅读:
    Neural Collaborative Filtering 神经网络协同过滤
    pyspark(一) 常用的转换操作
    HO引擎近况20210315
    LeetCode–前 K 个高频元素
    常用十大算法(七)— 克鲁斯卡尔算法
    常用十大算法(六)— 普里姆算法
    LeetCode–数值的整数次方
    LeetCode–二叉树的层次遍历 II
    常用十大算法(五)— 贪心算法
    LeetCode–二进制中1的个数
  • 原文地址:https://www.cnblogs.com/lochan/p/3877718.html
Copyright © 2011-2022 走看看