[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;
}
原文地址:https://www.cnblogs.com/ZH-comld/p/10181814.html