zoukankan      html  css  js  c++  java
  • tarjan缩点+拓扑排序 BZOJ2535 [Noi2010]Plane 航空管制

    2535: [Noi2010]Plane 航空管制2

    Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special Judge
    Submit: 818  Solved: 517
    [Submit][Status][Discuss]

    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

    HINT

    题目描述已经提示正解了,此题要反向存。

    存边,并将每架飞机的起飞限制x改成n-x,就将第一问转化成一个求飞机最晚起飞时间的问题,用拓扑排序可解。
    第二问:每次限制不起飞某架飞机p,而将其他能飞的飞机都飞出去(拓扑排序时不处理p结点,让p连出去的边都保留下来),此时飞机p必须起飞了,这个时间就是它在新问题中的最晚起飞时间,也就是原问题中的最早起飞时间。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 int n,m,cnt,hd,tl;
     7 struct data{
     8     int limit,num;
     9 }p[2010];
    10 struct dt{
    11     int nex,to;
    12 }edge[20010];
    13 int lim[2010],getin[2010],gtin[2010],head[2010],q[2010];
    14 bool cmp(const data&aa,const data&bb){
    15     return aa.limit<bb.limit;
    16 }
    17 void add(int start,int end){
    18     edge[++cnt].nex=head[start];
    19     edge[cnt].to=end;
    20     head[start]=cnt;
    21 }
    22 void work(int x){
    23     memcpy(gtin,getin,sizeof(getin));
    24     hd=tl=0;//!!!
    25     for(int t=1,i=1;i<=n;i++){
    26         /*for(int t=1;t<=n;t++)
    27             if(p[t].limit<i&&!gtin[p[t].num]&&x!=p[t].num) q[++tl]=p[t].num;*/
    28         for(;t<=n&&p[t].limit<i;t++)
    29             if(!gtin[p[t].num]&&p[t].num!=x) q[++tl]=p[t].num;  
    30         if(hd<tl){
    31             int u=q[++hd];
    32             for(int j=head[u];j;j=edge[j].nex){
    33                 gtin[edge[j].to]--;
    34                 if(!gtin[edge[j].to]&&x!=edge[j].to&&lim[edge[j].to]<i) q[++tl]=edge[j].to;
    35             }
    36         }
    37         else return;
    38     }       
    39 }
    40 int main(){
    41     scanf("%d%d",&n,&m);
    42     for(int i=1;i<=n;i++){
    43         scanf("%d",&p[i].limit);
    44         p[i].limit=n-p[i].limit;
    45         p[i].num=i;
    46         lim[i]=p[i].limit;
    47     }
    48     sort(p+1,p+n+1,cmp);
    49     int a,b;
    50     for(int i=1;i<=m;i++){
    51         scanf("%d%d",&a,&b);
    52         getin[a]++;
    53         add(b,a);
    54     }
    55     work(0);
    56     for(int i=tl;i>=2;i--) printf("%d ",q[i]);
    57     printf("%d
    ",q[1]);
    58     for(int i=1;i<n;i++){
    59         work(i);
    60         printf("%d ",n-tl);
    61     }
    62     work(n);
    63     printf("%d",n-tl);
    64     return 0;
    65 }
  • 相关阅读:
    省选模拟27
    省选模拟26
    省选模拟25
    省选模拟23
    PHP 各个框架的优缺点(超详细)
    windows 下安装中文版Git
    支付宝APP支付里设置应用网关和授权回调地址是不必填的
    linux服务器下安装phpstudy 如何命令行进入mysql
    js金钱转大写
    多个 (li) 标签如何获取获取选中的里面的某个特定值??
  • 原文地址:https://www.cnblogs.com/zwube/p/7260214.html
Copyright © 2011-2022 走看看