• 拓扑排序+不是字典序的优先级排列(POJ3687+HDU4857)


    一、前言

            在过去的一周里结束了CCSP的比赛,其中有一道题卡了我9个小时,各种调错都没法完整的调处来这题,于是痛下决心开始补题,这个是计划的一部分。事实上,基于错误的理解我写了若干发拓扑排序+字典序的算法,但是集体统一GG,最后发现,实际上要求设计的并不是严格意义上的最小字典序,而是“最小的必然放在最大的之前”这种看上去很类似但是时至完全不一样的说法。而这也是为什么,正想建树GG但是反向建树,用大顶堆来找最大的思路是正确的。这实际上等价于,“寻找最大字典序并且反向输出”这个过程。

    首先看一组样例

    1

    3 1

    3 1
            对于改组样例,有约束——3必须在1前面,因为如果有最小字典序正想输出的算法就会得到2 3 1。但是这个数据明显的违反了题目对于顺序的规约——“如果存在一个1,能够在2前面,那么就必须把1放到2前面,在这之后,如果还有2能够放在3前面,就必须把2放到3前面”。于是我们直觉上认为,这种说法其实等价于,首先把所有可能的最大值全放到最后,用以保证不会有任何一个合法的小数放到大数的后面。正确的做法是,2 1 3(逆向输出是3,1,2)。这种方法从玄学上保证了输出“依照题目意思有序”。

    二、思路和相关优化

            思路简单的讲就是拓扑排序过程中,通过检测是否有新的元素已经可以被当做随时可以加入队列的元素,如果有,就加入优先队列,如果没有就继续。

            一般来说,使用字典序输出拓扑排序是一件很简单的事情。对比了网上其他人写的代码,我们可以直观的认为至少有如下几种优化方式:

    1. 使用邻接表来存储具体的边信息而不是邻接矩阵。(可以证明,使用vector作为邻接表插入N条边的时间期望应当是O(N))
    2. 使用优先队列、multiset来从集合中选取最大最小的元素
    3. 使用CNT[]数组来记录该点被指向的次数,之后在topsort当中通过对cnt数组相应元素的判断来确定这个值是不是等于零

    三、通用AC代码

    POJ3687

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<set>
    #include<vector>
    #include<queue>
    using namespace std;
    
    const long long MAXN=30233;
    
    vector<int>G[MAXN];
    int cnt[MAXN];
    long long n,m;
    
    int vis[MAXN];
    bool dfs(int now)
    {
        vis[now]=1;
        int len=G[now].size();
        for(int i=0;i<len;++i)
        {
            int tar=G[now][i];
            if(vis[tar]==1)return true;
            if(vis[tar]==0&&dfs(tar))return true;
            
        }vis[now]=2;
        return false;
    }
    bool check_circle()
    {
        memset(vis,0,sizeof(int)*(n+5));
        for(int i=1;i<=n;++i)
        {
            if(vis[i]==0&&dfs(i))return true;
        }return false;
    }
    int ans[MAXN];
    void topSort()
    {
        priority_queue<int>q;
        int summ=n;
        for(int i=1;i<=n;++i)
        {
            if(cnt[i]==0)q.push(i);
        }
        while(!q.empty())
        {
            int now=q.top();q.pop();
            int len=G[now].size();
            ans[now]=summ--;
            for(int i=0;i<len;++i)
            {
                int tar=G[now][i];
                cnt[tar]--;
                if(cnt[tar]==0)q.push(tar);
            }
        }
    }
    
    void init()
    {
        memset(cnt,0,sizeof(int)*n+233);
        cin>>n>>m;
        for(int i=0;i<=n;++i)
        {
            G[i].clear();
        }
        for(int i=0;i<m;++i)
        {
            int a,b;
            cin>>a>>b;
            G[b].push_back(a);
            cnt[a]++;
        }
        if(check_circle())
        {
            cout<<"-1
    ";
            return ;
        }
        topSort();
        for(int i=1;i<=n;++i)
        {
            cout<<ans[i]<<" ";
        }cout<<endl;
    }
    
    int main()
    {
        cin.sync_with_stdio(false);
        int ca;
        cin>>ca;
        while(ca--)init();
        
        return 0;
    }

    HDU4857

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<set>
    #include<vector>
    #include<queue>
    using namespace std;
    
    const long long MAXN=30233;
    
    vector<int>G[MAXN];
    int cnt[MAXN];
    long long n,m;
    
    int vis[MAXN];
    bool dfs(int now)
    {
        vis[now]=1;
        int len=G[now].size();
        for(int i=0;i<len;++i)
        {
            int tar=G[now][i];
            if(vis[tar]==1)return true;
            if(vis[tar]==0&&dfs(tar))return true;
            
        }vis[now]=2;
        return false;
    }
    bool check_circle()
    {
        memset(vis,0,sizeof(int)*(n+5));
        for(int i=1;i<=n;++i)
        {
            if(vis[i]==0&&dfs(i))return true;
        }return false;
    }
    int ans[MAXN];
    void topSort()
    {
        priority_queue<int>q;
        int summ=n;
        for(int i=1;i<=n;++i)
        {
            if(cnt[i]==0)q.push(i);
        }
        while(!q.empty())
        {
            int now=q.top();q.pop();
            int len=G[now].size();
            ans[summ--]=now;
            for(int i=0;i<len;++i)
            {
                int tar=G[now][i];
                cnt[tar]--;
                if(cnt[tar]==0)q.push(tar);
            }
        }
    }
    
    void init()
    {
        memset(cnt,0,sizeof(int)*n+233);
        cin>>n>>m;
        for(int i=0;i<=n;++i)
        {
            G[i].clear();
        }
        for(int i=0;i<m;++i)
        {
            int a,b;
            cin>>a>>b;
            G[b].push_back(a);
            cnt[a]++;
        }
        if(check_circle())
        {
            cout<<"-1
    ";
            return ;
        }
        topSort();
        for(int i=1;i<n;++i)
        {
            cout<<ans[i]<<" ";
        }cout<<ans[n]<<endl;
    }
    
    int main()
    {
        cin.sync_with_stdio(false);
        int ca;
        cin>>ca;
        while(ca--)init();
        
        return 0;
    }
  • 相关阅读:
    deepin linux 安装 mysql
    Django根据现有数据库建立model
    轻松学习正则表达式
    ubuntu 下安装 wxpython2.8
    Robot framework + appium环境搭建
    使用 robotframework 自动化测试系列 二 -----环境搭建
    使用 robotframework 自动化测试系列 一 -----简介
    执行robot framework 的测试用例 命令行pybot使用方式
    SQLAlchemy的使用---外键ForeignKey数据库创建与连接
    SQLAlchemy的使用---增删改查
  • 原文地址:https://www.cnblogs.com/rikka/p/7760831.html
Copyright © 2020-2023  润新知