zoukankan      html  css  js  c++  java
  • BZOJ2109: [Noi2010]Plane 航空管制

    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个整数 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 4 1 2 1

    在样例 1 中:
    起飞序列 3 5 1 4 2 满足了所有的限制条件,所有满足条件的起飞序列有:
    3 4 5 1 2 3 5 1 2 4 3 5 1 4 2 3 5 4 1 2
    5 3 1 2 4 5 3 1 4 2 5 3 4 1 2
    由于存在(5, 1)和(3, 1)两个限制,航班1只能安排在航班 5和3之后,故最早
    起飞时间为3,其他航班类似。


    对于30%数据:n≤10;
    对于60%数据:n≤500;
    对于100%数据:n≤2,000,m≤10,000。
     
    我们发现这个问题直接做比较困难,考虑倒过来做。
    将原图反向,最晚时刻限定改成最早时刻限定,不难证明新问题的解与原题中的解一一对应。
    然而新问题好做多了,航班k出发的最晚时刻可以考虑在拓扑排序的时候先不管k航班,直到当前队列中没有元素了再将k加入,不难证明这就是航班k出发的最晚时刻,即原问题中航班k出发的最早时刻。
    时间复杂度为O(nm)。
    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
    	if(head==tail) {
    		int l=fread(buffer,1,BufferSize,stdin);
    		tail=(head=buffer)+l;
    	}
    	return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=2010;
    const int maxm=10010;
    int n,m,ans[maxn];
    struct Pair {
    	int v,p;
    	bool operator < (const Pair& ths) const {return v<ths.v;}
    }A[maxn];
    int p[maxn],q[maxn],first[maxn],deg[maxn],in[maxn],next[maxm],to[maxm],e;
    void AddEdge(int u,int v) {deg[v]++;to[++e]=v;next[e]=first[u];first[u]=e;}
    int solve(int k) {
    	rep(i,1,n) in[i]=deg[i];
    	int cur=1,l=1,r=0,x,res;
    	rep(j,1,n) {
    		while(cur<=n&&A[cur].v<=j) {
    			if(!in[A[cur].p]&&A[cur].p!=k) q[++r]=A[cur].p;
    			cur++;
    		}
    		if(l<=r) x=q[l++]; else return j;
    		ans[j]=x;
    		ren {
    			in[to[i]]--;
    			if(!in[to[i]]&&p[to[i]]<=j&&to[i]!=k) q[++r]=to[i];
    		}
    	}
    	return res;
    }
    int main() {
    	n=read();m=read();
    	rep(i,1,n) A[i]=(Pair){p[i]=n-read()+1,i};
    	rep(i,1,m) AddEdge(read(),read()); 
    	sort(A+1,A+n+1);
    	rep(i,1,n) printf("%d ",n-solve(i)+1);
    	return 0;
    }
    

      

  • 相关阅读:
    自定义容器,支持创建普通实例,单例,线程单例
    Unity创建实例:普通实例,单例,线程单例
    自定义容器,利用依赖注入创建对象
    容器Unity实现IOC+DI
    实现高层依赖低层通过抽象类来实现,保证项目的可扩展性
    接口,抽象类,继承,多态,重写
    Linux--如何实现虚拟机与主机之间的文件传输无需第三方,即可轻松设置共享文件夹(适合所有人群)
    Linux--常用的linux基本命令学习大全01(适合所有人群)
    reset.css下载
    vue项目中,'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5594278.html
Copyright © 2011-2022 走看看