BZOJ 2535: [Noi2010]Plane 航空管制2

Posted 人间失格

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2535: [Noi2010]Plane 航空管制2相关的知识,希望对你有一定的参考价值。

Description

世博期间,上海的航空客运量大大超过了平时,随之而来的航空管制也频频发生。最近,小X就因为航空管制,连续两次在机场被延误超过了两小时。对此,小X表示很不满意。 在这次来烟台的路上,小 X不幸又一次碰上了航空管制。于是小 X开始思考关于航空管制的问题。 假设目前被延误航班共有 n个,编号为 1至n。机场只有一条起飞跑道,所有的航班需按某个顺序依次起飞(称这个顺序为起飞序列)。定义一个航班的起飞序号为该航班在起飞序列中的位置,即是第几个起飞的航班。 起飞序列还存在两类限制条件: ? 第一类(最晚起飞时间限制):编号为 i的航班起飞序号不得超过 ki; ? 第二类(相对起飞顺序限制):存在一些相对起飞顺序限制(a, b),表示航班 a的起飞时间必须早于航班 b,即航班 a的起飞序号必须小于航班 b 的起飞序号。 小X 思考的第一个问题是,若给定以上两类限制条件,是否可以计算出一个可行的起飞序列。第二个问题则是,在考虑两类限制条件的情况下,如何求出每个航班在所有可行的起飞序列中的最小起飞序号。

Input

第一行包含两个正整数 n和m,n表示航班数目,m表示第二类限制条件(相对起飞顺序限制)的数目。 第二行包含 n个正整数 k1, k2, „, kn。 接下来 m行,每行两个正整数 a和b,表示一对相对起飞顺序限制(a, b),其中1≤a,b≤n, 表示航班 a必须先于航班 b起飞。

Output

由两行组成。 
第一行包含 n个整数,表示一个可行的起飞序列,相邻两个整数用空格分隔。
输入数据保证至少存在一个可行的起飞序列。如果存在多个可行的方案,输出任
意一个即可。 
第二行包含 n个整数 t1, t2, „, tn,其中 ti表示航班i可能的最小起飞序
号,相邻两个整数用空格分隔。

Sample Input

5 5
4 5 2 5 4
1 2
3 2
5 1
3 4
3 1

Sample Output

3 5 1 4 2
3 4 1 2 1

 

 

题解:

  这个题目好难想,首先第一问还是比较套路的,我们对于n个点,连一个反图,拓扑排序一下,丢到一个按照点权排序的大根堆了面,正确性还是比较显然的,我们按照拓扑排序的顺序,那么一定满足了条件二的限制,那么用堆来搞,他们的点权就是他们的承受能力,那么承受能力强的排在后面,如果这样还不行,那么此题一定无解,(为什么正着做是错的我也不知道)。

  然后第二问就比较难想了,我们枚举当前要计算答案的点,那么考虑拓扑排序的时候不把他丢到堆里面,直到出现不合法情况的时候,这个时候,就是他最早出现的位置,因为此刻如果还不放他进去,那么必然序列会不合法,所以这个时刻就是这个点的ans.

 

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <queue>
#define MAXN 200050
#define RG register
using namespace std;
struct node{
    int id,v;
    bool operator < (const node&x)const{
        return x.v>v;
    }
};

struct edge{
    int first;
    int next;
    int to;
    int quan;
}a[MAXN*2];

priority_queue<node> q;
int v[MAXN],in[MAXN],in2[MAXN],ans[MAXN];
int n,m,num=0;

void addedge(int from,int to){
    a[++num].to=to;
    a[num].next=a[from].first;
    a[from].first=num;
}

inline void work1(){
    for(RG int i=1;i<=n;i++) in2[i]=in[i];
    for(RG int i=1;i<=n;i++){
        if(!in2[i]) q.push((node){i,v[i]});
    }
    while(!q.empty()){
        int now=q.top().id;q.pop();
        ans[++num]=now;
        for(RG int i=a[now].first;i;i=a[i].next){
            int to=a[i].to;
            in2[to]--;
            if(!in2[to]) q.push((node){to,v[to]});
        }
    }
}

inline int work2(int k){
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;i++) in2[i]=in[i];
    for(int i=1;i<=n;i++){
        if(i!=k&&!in2[i]) q.push((node){i,v[i]});
    }
    for(RG int hh=n;hh>=1;hh--){
        if(q.empty()||q.top().v<hh) return hh;
        int now=q.top().id;q.pop();
        for(RG int i=a[now].first;i;i=a[i].next){
            int to=a[i].to;
            in2[to]--;
            if(!in2[to]&&to!=k) q.push((node){to,v[to]});
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&v[i]);
    for(int i=1;i<=m;i++){
        int x,y;scanf("%d%d",&x,&y);
        addedge(y,x);in[x]++;
    }
    num=0;
    work1();
    for(int i=num;i>=1;i--) printf("%d ",ans[i]);puts("");
    for(int i=1;i<=n;i++) printf("%d ",work2(i));
    printf("\n");
    return 0;
}

 

以上是关于BZOJ 2535: [Noi2010]Plane 航空管制2的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2535: [Noi2010]Plane 航空管制2

bzoj 2109: [Noi2010]Plane 航空管制

BZOJ2109 NOI2010 Plane 航空管制 拓扑排序

BZOJ 2535 Plane 航空管制2

bzoj 2007: [Noi2010]海拔

BZOJ 2007: [Noi2010]海拔