這道題做法很簡單,年鑑上講的很複雜的樣子……
首先第一問,對於每個節點來說,他肯定要比自己的後繼先,在此基礎上越往後越好(盡量滿足限制嚴格的其他點)
那麼可以將乙個節點i的k更新為min(k[i],k[j]-1)j為i的後繼
注意更新的時候要按照拓撲序來,否則有可能更新不完全//他兒子還沒更新完就更新他了
//我一開始沒有注意拓撲序,後面懶得改了仿照bellman-ford在外面再套了一層控制次數,於是超慢……
最後按照這個k排序輸出即可,可以證明這樣一定滿足條件
重點是第二問
對於每個點i,首先dfs一下,那麼他肯定要放在他這棵子樹的所有點的後面 //實際上不是棵樹,但還是認為是一棵樹吧
記當前答案為ans ,已經放了cnt個點了,那麼初始cnt=ans,然後每訪問乙個沒放到序列中的點,cnt++
然後對於其他的點,按照第一問求得的k從小到大訪問
有可能存在點的k>ans,意味著這個點一定要放在ans前面,那麼ans++
還有可能存在點的k<=cnt,也就是說點i無論如何一定要放在這個點後面,否則怎樣都無法滿足,那麼ans=k+1
然後搞定……
//lib #include#include#include#include#include#include#include#include#include#includeusing namespace std; //macro #define rep(i,a,b) for(int i=a,tt=b;i<=tt;++i) #define drep(i,a,b) for(int i=a,tt=b;i>=tt;--i) #define erep(i,e,x) for(int i=x;i;i=e[i].next) #define irep(i,x) for(__typedef(x.begin()) i=x.begin();i!=x.end();i++) #define read() (strtol(ipos,&ipos,10)) #define sqr(x) ((x)*(x)) #define pb push_back #define ps system("pause"); typedef long long ll; typedef pairpii; const int oo=~0u>>1; const double inf=1e100; const double eps=1e-6; string name="plane",in=".in",out=".out"; //var struct plane } a[i]=ans; } rep(i,1,n-1)printf("%d ",a[i]); printf("%d\n",a[n]); } void work() int main()
NOI2010 航空管制
二元組的限制 考慮拓撲排序 正向拓撲不能保證最優,因卡的是結束時間 所以方向建圖topo 從n為0時間,相當於在n k i 的時間出現一架飛機 小根堆維護,每次選擇當前最早出現的一架飛機起飛。由於保證有解,這個顯然是正確的,對於當前只有一架飛機,不飛白不飛 當然也不能不飛 多架飛機,先飛後飛反正都是...
NOI2010 航空管制
首先第一問是很好做的,因為題目中保證有合法解,所以我們盡量讓期限晚的航班晚起飛.所以就是反著建圖,按照拓撲序給每個航班安排時間.第二問要求問所有合法解中每個航班最早什麼時候能起飛.那麼還是參考第一問的思路,額外的一點就是讓能安排在它後面的航班都安排到後面.所以就是先限制不選它,直到剩下的沒有辦法再選...
NOI2010 航空管制
貪心。對於第1個問,我們先建立拓撲圖,對於如果a必須在b前起飛,那麼連有向邊b a,並求出點的入度。將所有入度為0的點放在乙個優先佇列裡,按最大起飛編號從大到小排序。我們從後往前考慮起飛的航班。取出優先佇列中最大起飛編號最大的點,作為最後乙個航班,並刪去拓撲圖中與他相連的邊,如果有新的點的入度變成0...