The lexicographically smallest topological sort is built by Kahn's algorithm with a priority queue: at each step, among all available vertices (vertices that have no incoming edges from vertices not yet written out), the vertex with the smallest number is chosen.
An added edge u \to v makes the vertex unavailable until the vertex is written out. So by adding edges we can "hide" small vertices and thereby force the algorithm to choose vertices with larger numbers. Each hidden vertex costs one edge from the budget .
The greedy idea. We build the answer position by position. Lexicographic comparison is decided by the first differing position, so at each position we must place the vertex with the largest possible number — no gains at later positions can compensate for a loss at the current one.
We divide the vertices that can be written out at the current step into two sets:
— the available vertices: all edges entering them have already been "removed". If we do nothing, Kahn's algorithm chooses the smallest vertex of ;
— the deferred vertices. These are vertices that were available, but we decided to hide them. For each such vertex we commit to adding an edge entering it. We choose the start of this edge later — it will be the vertex written out immediately before the deferred one.
The set is stored in a priority queue with the smallest element on top (a min-heap), and the set in a priority queue with the largest element on top (a max-heap).
When it pays to defer a vertex. Let be the smallest vertex in . If we leave it alone, will be placed at the current position. Deferring (spending an edge) makes sense in two cases:
contains at least two vertices. Then, after is deferred, the next vertex of in increasing order, which is greater than , will be placed at the current position;
contains only the vertex , but contains a deferred vertex y > x. Then, after is deferred, the set becomes empty, and the largest deferred vertex — a number greater than — will be placed at the current position.
In all other cases deferring does not increase the number at the current position, and there is no need to spend an edge. We defer vertices one at a time, starting with the smallest, as long as it pays off and the budget is not exhausted.
Which vertex to write out. After deferring:
if is not empty, we write out the smallest vertex of — this is required by the rule of the lexicographically smallest sort;
if is empty, we write out the largest deferred vertex from and add an edge from the last written vertex to . It is exactly this edge that "hid" the vertex : until now it was unavailable, and now, when its new predecessor has been written out, it becomes the only available vertex. The other deferred vertices remain hidden — their edges will be added later.
Then, as usual in Kahn's algorithm, we decrease the in-degrees of the neighbours of the written vertex; vertices whose in-degree becomes zero are added to .
Why the answer is correct. Every deferred vertex is sooner or later written out from , and exactly one edge is added at that moment. Therefore the number of added edges equals the number of deferrals and does not exceed . All added edges go from a vertex written out earlier to a vertex written out later, so the found order is a topological sort of the new graph and no cycles appear.
Complexity. Each vertex enters at most once and at most once, and each edge of the graph is examined once. The total complexity is O((n + m) \log n).
Algorithm for Solving the Problem
We use Kahn's algorithm and two priority queues:
— min-heap that stores available vertices, with the smallest-numbered vertex at the top.
— max-heap that stores deferred vertices, with the largest-numbered vertex at the top.
Declare the following arrays:
indeg[v] — the number of incoming edges of vertex that have not yet been processed;
— the resulting topological ordering;
— the list of added edges.
Step 1. Initialization
Compute the in-degree of every vertex.
Add all vertices with zero in-degree to .
Initialize and the list as empty.
Step 2. Constructing the Answer
While not all vertices have been processed:
1. Defer a vertex if it is beneficial.
While the number of added edges is less than , heap is not empty, and at least one of the following conditions holds:
contains at least two vertices;
contains a single vertex , and contains a vertex such that y > x.
Extract the smallest vertex from and insert it into . This vertex will be processed later.
2. Choose the Next Vertex.
If is not empty, extract the smallest vertex from it.
Otherwise, extract the largest vertex from . If is not empty, add an edge from the last vertex in to .
Append to the end of .
3. Update the Graph.
For each outgoing edge v \to u:
Decrease indeg[u] by one.
If indeg[u] becomes zero, add to .
Repeat these steps until all vertices have been added to .
Step 3. Output
Print the sequence .
Print the number of added edges.
Print the added edges themselves.
Example
Consider the example from the statement: n = 5, k = 2, edges 1 \to 4, 4 \to 2, 1 \to 3. Initial in-degrees: vertices and have in-degree , vertices have in-degree . The initial sets are A = \{1, 5\}, B = \{\,\}.
Step | Deferred | Take | Edge | Order | |||
(two vertices in ) | from | — | |||||
— | from | 5 \to 1 | |||||
(two vertices in : and ) | from | — | |||||
— (k = 0) | from | — | 5, 1, 4, 2 | ||||
— | from | 2 \to 3 | 5, 1, 4, 2, 3 |
Let us go through the steps in more detail.
Step 1. A = \{1, 5\} contains two vertices, so we defer the smallest one — . Now A = \{5\} contains one vertex, and has no vertices greater than , so we stop deferring. We write out .
Step 2. is empty. We write out the largest deferred vertex and add the edge 5 \to 1. We remove the edges 1 \to 4 and 1 \to 3: vertices and become available, A = \{3, 4\}.
Step 3. contains two vertices — we defer , and the edge budget is exhausted (k = 0). We write out , after which the edge 4 \to 2 is removed and A = \{2\}.
Step 4. No more deferrals are possible. We write out .
Step 5. is empty. We write out the deferred vertex and add the edge 2 \to 3.
We obtain the order 5, 1, 4, 2, 3 and the added edges 5 \to 1 and 2 \to 3. The original graph (left) and the graph with the added edges (right, the added edges are shown in red):
Without added edges the lexicographically smallest sort is 1, 3, 4, 2, 5: vertex is not connected to anything, but because of its large number it is chosen last. After two edges are added, vertex comes first, and the order 5, 1, 4, 2, 3 is lexicographically larger.
Consider one more example, in which four vertices are available at the beginning. Let n = 8, m = 6, k = 4, and let the edges of the graph be 6 \to 3, 4 \to 8, 3 \to 5, 1 \to 7, 2 \to 7, 5 \to 7.
No edge enters vertices 1, 2, 4, 6, so at the beginning A = \{1, 2, 4, 6\}, B = \{\,\}. Without added edges the lexicographically smallest sort is 1, 2, 4, 6, 3, 5, 7, 8.
The original graph (left) and the graph after adding edges (right, the added edges are shown in red)
Step | before | before | Deferred | Take | Edge | |
\{1, 2, 4, 6\} | from | — | ||||
\{4, 2, 1\} | 3~(4 > 3) | from | 6 \to 4 | |||
\{3, 2, 1\} | — | from | — | |||
\{3, 2, 1\} | — | from | 8 \to 3 | |||
— | from | — | ||||
— | from | 5 \to 2 | ||||
— | from | 2 \to 1 | ||||
— | from | — |
Let us go through the steps in more detail.
Step 1. A = \{1, 2, 4, 6\}, k = 4. We defer vertex , since contains four vertices, then (three vertices in ), then (two vertices in ). The budget decreases to k = 1. Now A = \{6\} contains one vertex, and the largest deferred vertex is less than — further deferring does not pay off. We write out . The edge 6 \to 3 is removed, and A = \{3\}.
Step 2. A = \{3\}, B = \{4, 2, 1\}, k = 1. contains one vertex, but contains the vertex 4 > 3, so we defer as well; the budget is exhausted, k = 0. is empty — we write out the largest deferred vertex and add the edge 6 \to 4. The edge 4 \to 8 is removed, and A = \{8\}.
Step 3. No more deferrals are possible. We write out , after which is empty.
Step 4. We write out the largest deferred vertex and add the edge 8 \to 3. The edge 3 \to 5 is removed, and A = \{5\}.
Step 5. We write out . The edge 5 \to 7 is removed, but edges from and still enter vertex , so is empty.
Step 6. We write out the deferred vertex and add the edge 5 \to 2. The edge 2 \to 7 is removed.
Step 7. We write out the deferred vertex and add the edge 2 \to 1. The edge 1 \to 7 is removed, and A = \{7\}.
Step 8. We write out .
The answer:
6 4 8 3 5 2 1 7
4
6 4
8 3
5 2
2 1This example clearly shows all cases of the algorithm. At step three vertices are deferred at once — as long as contains at least two vertices. At step the second condition applies: contains only vertex , but contains the larger vertex , so is deferred as well. Deferred vertices leave in decreasing order (4, 3, 2, 1), and each of them receives exactly one edge from the vertex written out before it. Therefore exactly as many edges are added as there were deferrals — four.
Algorithm implementation
Read the input data. Construct the graph. The adjacency lists are stored in , the in-degrees in .
scanf("%d %d %d", &n, &m, &k);
vector<vector<int>> g(n + 1);
vector<int> indeg(n + 1, 0);
for (int i = 0; i < m; i++)
{
scanf("%d %d", &u, &v);
g[u].push_back(v);
indeg[v]++;
}Declare two priority queues: — the available vertices, with the smallest element on top (a min-heap); — the deferred vertices, with the largest element on top (a max-heap).
priority_queue<int, vector<int>, greater<int>> A; // available, min-heap
priority_queue<int> B; // deferred, max-heapInitially all vertices with zero in-degree are available.
for (int v = 1; v <= n; v++)
if (indeg[v] == 0) A.push(v);The array accumulates the answer — the required topological sort, and the array stores the added edges.
vector<int> order;
order.reserve(n);
vector<pair<int, int>> added;Each iteration of the loop adds one vertex to the answer, until all vertices are written out.
while ((int)order.size() < n)
{Defer vertices. While there are edges left in the budget and the set is not empty, consider the smallest available vertex . It pays to defer it if contains at least one more vertex or if contains a deferred vertex with a larger number. A deferred vertex is moved from to , and the budget decreases by . Otherwise deferring stops.
// defer vertices while it pays off and edges remain
while (k > 0 && !A.empty())
{
int x = A.top();
if (A.size() >= 2 || (!B.empty() && B.top() > x))
{
A.pop();
B.push(x);
k--;
}
else break;
}Choose the vertex to be written out at the current position. If is not empty, it is the smallest available vertex. Otherwise we take the largest deferred vertex and add an edge from the last written vertex order.back() to .
int v;
if (!A.empty())
{
v = A.top();
A.pop();
}
else
{
v = B.top();
B.pop();
added.push_back(make_pair(order.back(), v));
}Append to the answer and, as in Kahn's algorithm, decrease the in-degrees of its neighbours. Vertices whose in-degree becomes zero become available.
order.push_back(v);
for (int to : g[v])
if (--indeg[to] == 0) A.push(to);
}Print the found topological sort, the number of added edges and the edges themselves.
for (int i = 0; i < n; i++)
printf("%d ", order[i]);
printf("\n%d\n", added.size());
for (auto &e : added)
printf("%d %d\n", e.first, e.second);