1. 程式人生 > >[NOI2010]航空管制(拓撲排序+貪心)

[NOI2010]航空管制(拓撲排序+貪心)

spa namespace 排序 turn ostream 序號 span 一個 htm

題目描述

世博期間,上海的航空客運量大大超過了平時,隨之而來的航空管制也頻頻發生。最近,小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; }

[NOI2010]航空管制(拓撲排序+貪心)