• [NOI2010]航空管制(拓扑排序+贪心)


    题目描述

    世博期间,上海的航空客运量大大超过了平时,随之而来的航空管制也频频发生。最近,小X就因为航空管制,连续两次在机场被延误超过了两小时。对此,小X表示很不满意。

    在这次来烟台的路上,小X不幸又一次碰上了航空管制。于是小X开始思考关于航空管制的问题。

    假设目前被延误航班共有n个,编号为1至n。机场只有一条起飞跑道,所有的航班需按某个顺序依次起飞(称这个顺序为起飞序列)。定义一个航班的起飞序号为该航班在起飞序列中的位置,即是第几个起飞的航班。

    起飞序列还存在两类限制条件:

    • 第一类(最晚起飞时间限制):编号为i的航班起飞序号不得超过ki;

    • 第二类(相对起飞顺序限制):存在一些相对起飞顺序限制(a, b),表示航班a的起飞时间必须早于航班b,即航班a的起飞序号必须小于航班b的起飞序号。

    小X思考的第一个问题是,若给定以上两类限制条件,是否可以计算出一个可行的起飞序列。第二个问题则是,在考虑两类限制条件的情况下,如何求出每个航班在所有可行的起飞序列中的最小起飞序号。

    题解

    我好菜啊。。

    对于第一问,我们可以倒着贪心,尽量把k大的往后放,搞一个以k为关键字的大根堆,在反图上拓扑一下就可以了,我在这想了半天,太菜了。。。

    对于第二问,我们还是倒着放,和上边一样,这次我们不在堆中放i这个点,直到出现一个不合法的点出现,这时我们再加入i点就可以了。

    这样的思路和这道题一样。

    代码

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define N 2002
    #define M 10002
    using namespace std;
    int k[N],n,m,tot,head[N],du[N],num,pos[N],ans[N],d[N];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    struct edge{int n,to;}e[M];
    inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
    struct node{
        int id;
        inline bool operator <(const node &b)const{return k[id]<k[b.id];}
    };
    struct wf{int u,v;}b[M];
    priority_queue<node>q;
    int main(){
        n=rd();m=rd();
        for(int i=1;i<=n;++i)k[i]=rd();
        for(int i=1;i<=m;++i){
            b[i].u=rd();b[i].v=rd();
            add(b[i].v,b[i].u);d[b[i].u]++;
        }
        memcpy(du,d,sizeof(d));
        for(int i=1;i<=n;++i)if(!du[i])q.push(node{i});
        while(!q.empty()){
            int u=q.top().id;q.pop();num++;pos[num]=u;
            for(int i=head[u];i;i=e[i].n){
                int v=e[i].to;
                if(!--du[v])q.push(node{v});
            }
        }
        for(int i=n;i>=1;--i)printf("%d ",pos[i]);puts("");
        for(int o=1;o<=n;++o){
            while(!q.empty())q.pop();
            memcpy(du,d,sizeof(d));
            for(int i=1;i<=n;++i)if(!du[i]&&i!=o)q.push(node{i});
            for(int g=n;g>=1;--g){ 
                if(q.empty()){ans[o]=g;break;}
                int u=q.top().id;q.pop();
                if(k[u]<g){ans[o]=g;break;}
                for(int i=head[u];i;i=e[i].n){
                    int v=e[i].to;
                    if(!--du[v]&&v!=o)q.push(node{v});
                }
            }
        } 
        for(int i=1;i<=n;++i)printf("%d ",ans[i]);
        return 0;
    }
  • 相关阅读:
    Spring Session Logout
    VC6.0 error LNK2001: unresolved external symbol _main解决办法
    JDBC数据库编程基本流程
    JDBC连接SQL Server2008
    JDK的下载、安装及环境变量的配置
    奇数阶幻方口诀
    ping: sendto: Network is unreachable
    new/delete和malloc/free的区别
    MFC的消息管理
    VC++之自定义消息
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10181814.html
Copyright © 2020-2023  润新知