[CF825E] Minimal Labels(反向建图,拓扑排序)

题目链接: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?'
':' ');
40         }
41     }
42     return 0;
43 }
原文地址:https://www.cnblogs.com/kirai/p/7349954.html