[Noi2010]航空管制

来自FallDream的博客,未经允许,请勿转载, 谢谢。


 

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

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

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

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

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

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

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

n<=2000 m<=10000 

 

第一问 倒着括扑排序,然后每次选择一个限制时间最晚的飞机起飞即可 

我不会告诉你我一开始倒着改一下时间然后正着括扑排序的

然后第二个问,对不同的飞机分开计算,忽视目前计算的飞机,直到发现没有飞机可以起飞了,那么那个时间点就是答案啦。

复杂度n^2logn

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define MN 2000
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

int n,m,head[MN+5],t[MN+5],cnt=0,top=0,q[MN+5],in[MN+5],In[MN+5];
struct edge{int to,next;}e[20005];
priority_queue<pa> Q;
inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;++in[t];}

int Solve(int x)
{
    memcpy(in,In,sizeof(in));
    in[x]=n;while(!Q.empty()) Q.pop();
    for(int i=1;i<=n;++i) if(!in[i]) Q.push(mp(t[i],i));
    for(int i=n;i;--i)
    {
        if(Q.empty()||Q.top().first<i) return i;
        int x=Q.top().second;Q.pop();
        for(int i=head[x];i;i=e[i].next)
            if(!--in[e[i].to]) Q.push(mp(t[e[i].to],e[i].to));    
    }
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i) t[i]=read(); 
    for(int i=1;i<=m;++i) 
    {
        int x=read(),y=read();
        ins(y,x);
    }
    memcpy(In,in,sizeof(In));
    for(int    i=1;i<=n;++i) if(!in[i]) Q.push(mp(t[i],i));
    while(!Q.empty())
    {
        int x=Q.top().second;Q.pop();q[++top]=x;
        for(int i=head[x];i;i=e[i].next)
            if(!--in[e[i].to]) Q.push(mp(t[e[i].to],e[i].to));        
    }    
    for(;top;--top) printf("%d ",q[top]);puts("");
    for(int i=1;i<=n;++i) printf("%d ",Solve(i));
    return 0;
}

转载于:https://www.cnblogs.com/FallDream/p/Noi2010d2t1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值