Table of Contents
Part 1 - shortest-path algorithmsSubtasks 1 and 3 - breaking Floyd-WarshallCodeSubtasks 2 and 5 - breaking Bellman-FordCodeSubtasks 4 and 6 - breaking DijkstraCodePart 2 - the "mystery" problemSubtask 7 - forcing TLECodeSubtask 8 - forcing not TLECodeSolution: Subtasks 1-6Edit on GithubAPIO 2013 - Taskauthor
Author: Andi Qu
Table of Contents
Part 1 - shortest-path algorithmsSubtasks 1 and 3 - breaking Floyd-WarshallCodeSubtasks 2 and 5 - breaking Bellman-FordCodeSubtasks 4 and 6 - breaking DijkstraCodePart 2 - the "mystery" problemSubtask 7 - forcing TLECodeSubtask 8 - forcing not TLECodeSolution: Subtasks 1-6Edit on Github
Part 1 - shortest-path algorithms
In this subproblem, we're asked to create test cases that break certain shortest-path algorithms through TLE.
This is very educational because it forces you to analyze the bottlenecks of these algorithms and how exactly they work.
Subtasks 1 and 3 - breaking Floyd-Warshall
The Floyd-Warshall algorithm always uses exactly iterations.
This means we can simply set to 101 and to 0 to force TLE.
Code
1print(101) # Generate the graph2for i in range(101):3 print(0)45print(1) # Single query6print(0, 1)
Subtasks 2 and 5 - breaking Bellman-Ford
The Bellman-Ford algorithm normally uses exactly iterations, but in this case, it's slightly optimized.
However, we can still force the algorithm to use exactly iterations.
Firstly, note that we must have or else the algorithm will break early.
If we look at the implementation of this specific Bellman-Ford algorithm, note that we "relax" edges connected to node 1, then node 2, etc.
This means that if we have a straight line from node to node 0 (and no other edges), then only 1 edge will be relaxed per loop!
We can also add some self-edges (with positive weights) from node 0 to itself to increase without triggering an early break, since it's never optimal to go from a node to itself via a self-edge.
for subtask 2 and for subtask 5 let us force TLE.
Code
1print(300) # Change (300, 48) to (100, 1011) for subtask 22print(48, end=' ')3for i in range(48):4 print(0, 1, end=' ') # Self edges5print()6for i in range(1, 300):7 print(1, i - 1, 1)89print(10) # 10 queries10for i in range(10):
Subtasks 4 and 6 - breaking Dijkstra
At first glance, these subtasks seem impossible - Dijkstra's algorithm always has a complexity of !
... or does it?
Note that the complexity is only true if there are no negative edges.
What happens when we have negative edges in the graph? Consider the following construction:
o ^ \ 1 / \ -2 / v o------>o--->... 0
If there were no negative edges, then we'd only iterate through the edges connected to the rightmost node once.
However, notice how in the above construction, we will iterate through those edges twice.
This means that if we chain of those triangles together, then Dijkstra's algorithm will use iterations - far more than the expected !
Using 16 triangles, we are able to force TLE.
Code
1print(33)2print(0)3print(1, 0, 1)4print(1, 1, 1)5for i in range(2, 31, 2):6 print(1, i, -2 * (2**(i//2)))7 print(2, i + 1, 2**(i//2), i, 0)89print(7)10for i in range(7):
Part 2 - the "mystery" problem
Subtask 7 - forcing TLE
This section is not complete.
Code
1print(250, 1501)2for i in range(300):3 for j in range(i + 1, 250, i + 1):4 print(i, j)5for i in range(88):6 print(1, 2 * i + 3)
Subtask 8 - forcing not TLE
This section is not complete.
Code
1print(753, 1501)2for i in range(1, 752):3 if i != 1:4 print(0, i)5 print(i, 752)
C++
Solution: Subtasks 1-6
1int main() {2 FOR(TC,1,7) {3 setOut("apio-2013-taskauthor_"+ts(TC)+".out");4 int V;5 vpi adj[300];6 vpi query;7 if (TC == 1 || TC == 3) {8 V = 101;9 query.pb({0,0});10 } else if (TC == 2) {
Java
Python
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!