Minimal Labels CodeForces - 825E (反向拓撲排序+優先佇列)
阿新 • • 發佈:2018-12-26
題意:有一個有向無環圖,然後要給每個結點附上標籤,如果從v到u有一條邊,那麼v的標籤小於u的標籤,那麼v的標籤要小於u的標籤,最後使得從頂點1到頂點n的字典序最小,輸出這個字典序
題解:這題一眼看上去用拓撲排序,然後拍了個正向拓撲排序+每次找出最小的進入佇列中進行查詢,wa6,仔細分析一波,如果圖示這樣的
那麼按照正向拓撲的方法下來排序是1423,實際上答案是1342,這就得考慮一個問題就是真正的讓標號小的標籤也小,那麼應該怎麼做呢?使用反向拓撲排序,使用大根堆進行入隊,然後從後往前賦值,就完美的解決了這個問題。
附上程式碼:
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+50; int cnt[maxn],used[maxn],ans[maxn]; struct edge{ int u,v,next; }edges[maxn]; int head[maxn],tot; void add_edge(int a,int b) { edges[tot].u=a; edges[tot].v=b; edges[tot].next=head[a]; head[a]=tot++; } int main() { int n,m; memset(head,-1,sizeof(head)); tot=0; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); add_edge(v,u); cnt[u]++; } priority_queue<int>q; for(int i=1;i<=n;i++){ if(cnt[i]==0){ q.push(i); } } int temp=n; while(!q.empty()){ int u=q.top(); ans[u]=temp--; used[u]=true; q.pop(); for(int i=head[u];i!=-1;i=edges[i].next){ int to=edges[i].v; if(used[to]==true){ continue; } cnt[to]--; if(cnt[to]==0){ q.push(to); } } } printf("%d",ans[1]); for(int i=2;i<=n;i++){ printf(" %d",ans[i]); } return 0; }