/AlgoPA2

Primary LanguagePython

Steve Cobb
Algorithms Programming Assignment 2

Usage: 
$ ./RUN.py <file>

Output is to stdout.

Pseudocode:

Create list of edges (transactions) along with the time the transaction executes. O(m)

While creating edges, add entries to a hash table node_to_edge at the key [node_id] where 
the value is a list of edges. Thus, node_to_edge[node_id] points to a list of all incident 
edges upon node n with id node_id by the time all edges are created. O(m)

Initialize a global variable path (list of nodes) whose only element is designated start_node.
Begin modified DFS to update this path:

DFS(start_node, target_node, start_time, target_time)
    if start_time > target_time:
        # unsuccessful; backtrack
        remove last node from path
        return path
    if start_node == target_node:
        # path completed successfully
        return path
    for each edge e incident on start_node:
        mark edge so we won't traverse it again
        if e's other node n' is not in our path and start_time < e's time:
            # recursive call
            add n' to our path
            DFS(start_node = n', target_node=target_node, start_time = e's time, target_time=target_time)
    
    if last node on path is not target_node:
        #unsuccessful after; backtrack
        remove last node on path

At this point, path will either be the full path from start_node to target_node or it
will be empty.

Time Complexity:

Creating the list and node_to_edge hash table takes O(m) time because we iterate over the edges,
and each edge has a fixed number of nodes (2). The addition of the edge to the node's list in the
hash table is constant time (assuming amortized doubling of lists).

The DFS processing is a slightly altered breadth-first search, which reduces the processing 
time from DFS's O(m+n) to O(m), as it will not traverse any components not connected to the 
start node, and our algorithm traverse each edge at most twice (once from its node1, once
from its node2). Thus, the entire algorithm is O(m).

Correctness:

Suppose this algorithm does not work. That is, suppose the path P returned is incorrect. P is either:
    1. An empty path when a successful path exists.
    2. A path with edges which do not meet the timing/connection criteria

Let us examine possibility 1 first. An empty P means our algorithm, on its last iteration, did not
have the correct target node at P's last index. This could have happened for two reasons:
    1.1. The initial start time was later than the target_time
    1.2. The DFS executed but failed to find the target_node using only edges with time before 
       target_time

In case 1.1, there is no successful path, and we've reached a contradiction. In case 1.2, each branch
of the DFS tree must have culminated only in edges that (1) did not lead to the target node or (2)
were past the target time. Thus, there is no successful path, and we've reached a contradiction.

Now let us examine possibilty 2. Let us assume that a node n exists in our path such that n was
added out of order. That is, n was added to our path before its parent, n-1, received the trans-
mission. That means that the edge connecting n and n-1 must have a time of some t0, while the
edge between n-1 and its parent n-2 must have some time t1 > t0. But that means that in the exe-
cution of the above algorithm, n would never have been added to our path, because the time of the
edge (t0) would have been before the start_time for that execution of DFS (t1). Thus, we've reached
a contradiction, and this algorithm must be correct.