CS494 -- Lab 4 -- Our Friend Floyd


Your job is to do the 600 point problem from Topcoder SRM 626, D1. Here is the Problem Statement.. You don't have to do it topcoder-style (although you can do that to help you test). Instead, you need to read each set of parameters on standard input, each on its own line.

Since Topcoder's servers sometimes go down, here's a description of the problem tailored to how the lab is done:

I have the examples in text files in the lab directory. You can see their answers below. Comments on the examples: So you can see the format of the input, here's example 0:
UNIX> cat Example-0.txt
3
1 1 2  2 3 3
2 3 1  3 1 2
1 5 1 10 1 1
1
UNIX> NegativeGraphDiv1 < Example-0.txt
-9
UNIX> 
I have the rest of the topcoder examples in the lab directory as well:
UNIX> NegativeGraphDiv1 < Example-1.txt
-10000000
UNIX> NegativeGraphDiv1 < Example-2.txt
-9
UNIX> NegativeGraphDiv1 < Example-3.txt
-98765
UNIX> NegativeGraphDiv1 < Example-4.txt
-15328623718914
UNIX> time NegativeGraphDiv1 < Example-4.txt
-15328623718914
0.396u 0.004s 0:00.40 97.5%	0+0k 0+0io 0pf+0w
UNIX> 
Example 4 is kind of a big one, but it doesn't max out the constraints. I'll have some in the gradescripts that do max out the constraints.
UNIX> head -n 1 Example-4.txt
40
UNIX> sed -n 4p Example-4.txt | wc
      1     442    2593
UNIX> tail -n 1 Example-4.txt
160743953
UNIX> 
The gradescript will time your program, and you need to come in under two seconds of user time when compiled with -O2.

I'm not testing your error checking.


This problem has three components to it, and they all have a Floyd-Warshall flavor to them.

Part 1

This is the actual Floyd Warshall component. Make an adjacency matrix out of the smallest weight edges from each node to each other node (with zero-weight self-edges). Run Floyd-Warshall on that to create a matrix of shortest paths from every node to every other node. Call this matrix S. If charges equals 0, you can use this matrix to return the answer.

While you're at it, create an adjacency matrix that has the largest weight edges from every node to every other node (zero if there is no edge). Call that matrix L.

To help you, you can give an optional command line argument to my program (your program does not have to do this). If the argument is "P0", then the program will print out the original adjacency matrix, and if it's "P1", then the program will print out S:

UNIX> mv a.out NegativeGraphDiv1
UNIX> NegativeGraphDiv1 P0 < Example-0.txt
   6000000         1         5
         1   6000000        10
         1         1   6000000
-9
UNIX> NegativeGraphDiv1 P1 < Example-0.txt
         0         1         5
         1         0         6
         1         1         0
-9
UNIX> 

Part 2

Now create a new matrix, which we'll call A. This is going to be a matrix of shortest path lengths from each node to each other node, where there is exactly one negative edge used.

You make this by enumerating the following:

Consider the path f->i, (i,j), j->t, where the length of f->i and j->t come from S, and (i,j) is the longest edge from i to j (in L), multiplied by -1 to make it negative. Set A[f][t] to be the shortest of these for all i and j.

You can give my executable the argument "P2" to see my A matrix:

UNIX> NegativeGraphDiv1 P2 < Example-0.txt
        -8        -8        -9
        -9        -9       -10
        -8        -8        -9
-9
UNIX> 


Part 3

Now, you want to create a matrix Acharges for an arbitrary value of charges. Acharges is going to be the matrix of shortest paths from f to t that have exactly charges negative edges. If you have Ai and Aj, and x equals i+j, then you can make Ax from Ai and Aj. You do that by considering all paths from f to z (using Ai) and z to t (using Aj) for every possible intermediate node z.

Given that, you should be able to make any arbitrary Ax in O(log x) time.

If you give my executable "P3", it will print the final Acharges matrix. I won't show this on Example 0, since charges equals 1 there. Here's example 2:

UNIX> NegativeGraphDiv1 P0 < Example-2.txt
   6000000         1
         4   6000000
-9
UNIX> NegativeGraphDiv1 P1 < Example-2.txt
         0         1
         4         0
-9
UNIX> NegativeGraphDiv1 P2 < Example-2.txt
        -3        -6
        -4        -3
-9
UNIX> NegativeGraphDiv1 P3 < Example-2.txt
       -10        -9
        -7       -10
-9
UNIX> 

I don't know if you have analyzed running times yet, but Part 1 is O(N3), Part 2 is O(N4), and Part 3 is O(N3log(charges)).