来自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; }