题目描述
世博期间,上海的航空客运量大大超过了平时,随之而来的航空管制也频频发生。最近,小X就因为航空管制,连续两次在机场被延误超过了两小时。对此,小X表示很不满意。
在这次来烟台的路上,小X不幸又一次碰上了航空管制。于是小X开始思考关于航空管制的问题。
假设目前被延误航班共有n个,编号为1至n。机场只有一条起飞跑道,所有的航班需按某个顺序依次起飞(称这个顺序为起飞序列)。定义一个航班的起飞序号为该航班在起飞序列中的位置,即是第几个起飞的航班。
起飞序列还存在两类限制条件:
• 第一类(最晚起飞时间限制):编号为i的航班起飞序号不得超过ki;
• 第二类(相对起飞顺序限制):存在一些相对起飞顺序限制(a, b),表示航班a的起飞时间必须早于航班b,即航班a的起飞序号必须小于航班b的起飞序号。
小X思考的第一个问题是,若给定以上两类限制条件,是否可以计算出一个可行的起飞序列。第二个问题则是,在考虑两类限制条件的情况下,如何求出每个航班在所有可行的起飞序列中的最小起飞序号。
题解
我好菜啊。。
对于第一问,我们可以倒着贪心,尽量把k大的往后放,搞一个以k为关键字的大根堆,在反图上拓扑一下就可以了,我在这想了半天,太菜了。。。
对于第二问,我们还是倒着放,和上边一样,这次我们不在堆中放i这个点,直到出现一个不合法的点出现,这时我们再加入i点就可以了。
这样的思路和这道题一样。
代码
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #define N 2002 #define M 10002 using namespace std; int k[N],n,m,tot,head[N],du[N],num,pos[N],ans[N],d[N]; inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } struct edge{int n,to;}e[M]; inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;} struct node{ int id; inline bool operator <(const node &b)const{return k[id]<k[b.id];} }; struct wf{int u,v;}b[M]; priority_queue<node>q; int main(){ n=rd();m=rd(); for(int i=1;i<=n;++i)k[i]=rd(); for(int i=1;i<=m;++i){ b[i].u=rd();b[i].v=rd(); add(b[i].v,b[i].u);d[b[i].u]++; } memcpy(du,d,sizeof(d)); for(int i=1;i<=n;++i)if(!du[i])q.push(node{i}); while(!q.empty()){ int u=q.top().id;q.pop();num++;pos[num]=u; for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(!--du[v])q.push(node{v}); } } for(int i=n;i>=1;--i)printf("%d ",pos[i]);puts(""); for(int o=1;o<=n;++o){ while(!q.empty())q.pop(); memcpy(du,d,sizeof(d)); for(int i=1;i<=n;++i)if(!du[i]&&i!=o)q.push(node{i}); for(int g=n;g>=1;--g){ if(q.empty()){ans[o]=g;break;} int u=q.top().id;q.pop(); if(k[u]<g){ans[o]=g;break;} for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(!--du[v]&&v!=o)q.push(node{v}); } } } for(int i=1;i<=n;++i)printf("%d ",ans[i]); return 0; }