1. 程式人生 > >[CF825E] Minimal Labels(反向建圖,拓撲排序)

[CF825E] Minimal Labels(反向建圖,拓撲排序)

amp cto scanf i++ 題意 clear spa sin 字典序

題目鏈接:http://codeforces.com/problemset/problem/825/E

題意:給一個有向圖,求一個排列,這個排列是每一個點的序號,使得序號對應的點的排序符合拓撲序並且這個排列字典序最小。

直接跑字典序最小的拓撲排序是不行的,因為那樣只是確保點的字典序而非這個排列的字典序,比如這個數據:

10 1
5 2

反過來考慮,點號大的入度為0的點一定排在後面,這個位置確定了。但是點好小的入度為0的未必一定排在前面,因為這個點之前可能有入度不為0,但是與此點無關的點在前面,按題意這種點是要比當前點的序號小的。

反向建圖,跑字典序最大的拓撲排序就行了。

 1 #include <bits/stdc++.h>
 2
using namespace std; 3 4 const int maxn = 100100; 5 int n, m, cnt; 6 vector<int> G[maxn]; 7 int ret[maxn], in[maxn]; 8 priority_queue<int> pq; 9 10 void init() { 11 cnt = n; 12 memset(in, 0, sizeof(in)); 13 while(!pq.empty()) pq.pop(); 14 for(int i = 0; i < maxn; i++) G[i].clear();
15 } 16 17 signed main() { 18 // freopen("in", "r", stdin); 19 int u, v; 20 while(~scanf("%d%d",&n,&m)) { 21 init(); 22 for(int i = 0; i < m; i++) { 23 scanf("%d%d",&u,&v); 24 G[v].push_back(u); 25 in[u]++; 26 }
27 for(int i = 1; i <= n; i++) { 28 if(!in[i]) pq.push(i); 29 } 30 while(!pq.empty()) { 31 int u = pq.top(); pq.pop(); 32 ret[u] = cnt--; 33 for(auto v : G[u]) { 34 in[v]--; 35 if(in[v] == 0) pq.push(v); 36 } 37 } 38 for(int i = 1; i <= n; i++) { 39 printf("%d%c", ret[i], i==n?\n: ); 40 } 41 } 42 return 0; 43 }

[CF825E] Minimal Labels(反向建圖,拓撲排序)