Not All Roads Lead There

During a battle, Sheldor the conqueror notices that his cities are in the form of a Directed Acyclic Graph , i.e, all the roads are one-way and there is no sequence of roads starting from a city that comes back into it.

City 1 is completely under Sheldor's control and he uses it as the base shelter for his troops. He intends to send a number of troops to City 30. How many distinct paths could these troops take?


Input File: Link

Input Format and Details:

  • There are 30 cities numbered from 1 to 30.
  • Each line of the file contains two integers u v in that order. This means that there is a directed edge from u to v .
  • To reiterate, you need to find the number of paths from vertex 1 to vertex 30


The answer is 16.

This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try refreshing the page, (b) enabling javascript if it is disabled on your browser and, finally, (c) loading the non-javascript version of this page . We're sorry about the hassle.

3 solutions

Christopher Boo
Aug 18, 2016

For each node, we count and store the number of ways it can reach the final node. Let p a t h s ( i ) paths(i) be the number of ways to reach the final node. The number of ways for node i i to reach the final node is the sum of the number of ways of i i 's children to reach the final node. Mathematically, this is

p a t h ( i ) = j c h i l d ( i ) p a t h ( j ) path(i) = \sum_{j\in child(i)} path(j)

Arriving at this equation we know that we must find p a t h ( i ) path(i) in the correct order, ie if we haven't compute the p a t h ( j ) path(j) we cannot compute p a t h ( i ) path(i) . To deal with this, Agnishom's idea is to get the topological sort and compute p a t h ( ) path() according to that order. The definition of topological sort is that all children will be computed first before any of their parents, hence we will not miss out any children's p a t h ( ) path() . My solution is to straightly compute from the beginning node and recursively find its way to the final node - the idea of Depth-First Search.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <bits/stdc++.h>
using namespace std;

vector<int> adjList[35];
long long path[35];

// pay attention
void dfs(int node = 1) {
    if (node == 30)         // base case, 1 by default
        dp[node] = 1;
    if (path[node] != 0)    // compute already
        return;

    for (int i = 0; i < adjList[node].size(); i++) {
        int child = adjList[node][i];

        dfs(child);

        path[node] += path[child];
    }
}

int main() {

    for (int i = 0, u, v; i < 104; i++) {
        cin >> u >> v;

        adjList[u].push_back(v);
    }

    dfs();

    cout << path[1] << endl;

    return 0;
}

Nice straightforward approach. What is the time complexity of your solution?

Agnishom Chattopadhyay - 4 years, 10 months ago

Log in to reply

The time complexity is O ( E ) O(E) with E E the number of edges present in the graph.

Christopher Boo - 4 years, 10 months ago

Log in to reply

Great! I think that is fairly efficient.

Agnishom Chattopadhyay - 4 years, 10 months ago

Let us first parse the edge list to a more suitable form:

1
2
3
children = [[] for i in xrange(31)]
for edge in edgeList:
    children[edge[0]].append(edge[1])

Our idea is this, the number of paths from vertex i i to the sink is equal to the sum of the number of paths from each of the children of vertex i i to the sink. So, we could work backwards from the sink to the source adding up the number of paths at each step.

But how do we know that we've already computed the number of paths for each of the children of a particular node? To do that we approach the computation of reverse topological order of the vertices. (Recall that a topological ordering is a permutation of the vertices such that if there is a directed edge u v uv , u u appears after v v in the ordering).

Without full details on the topological sorting, here is how we implement it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def topoSort(children,N):
    L = []
    visited = [False for i in xrange(N+1)]
    def visit(u):
        if visited[u] == 'temp':
            raise Error
        if visited[u] == False:
            visited[u] = 'temp'
            for v in children[u]:
                visit(v)
            visited[u] = True
            L.append(u)
    for u in xrange(1,31):
        if visited[u] == False:
            visit(u)
    L.reverse()
    return L

And here is the main code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def countPaths(source, sink, children, N):
    topo = topoSort(children, N)
    sourceIndex, sinkIndex = map(topo.index,(source,sink))
    if sourceIndex > sinkIndex:
        return 0
    nPaths = [0 for i in xrange(N+1)]
    nPaths[sink] = 1
    i = sinkIndex
    while i != sourceIndex: 
        i -= 1
        for j in children[topo[i]]:
            nPaths[topo[i]] += nPaths[j]
    return nPaths[source]

print countPaths(1,30,children,30)

Abdelhamid Saadi
Dec 20, 2016

Deep first exploration in python 3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
graph = {}
nbpath = 0
def initgraph():   
    f = open('graph.txt')
    content = f.read().split('\n')
    f.close()
    for  str in content:
        [i, j] = [int(s) for s in str.split(" ")]
        if i in graph:
            graph[i].append(j)
        else:
            graph[i] = [j]

def godeep(city):
    global nbpath
    if city == 30:
        nbpath += 1
    elif city in graph:
        for x in graph[city]:
            godeep(x)

def solve(graph):
    "Not All Roads Lead There"
    initgraph() 
    godeep(1)
    return nbpath

print(solve(graph))

0 pending reports

×

Problem Loading...

Note Loading...

Set Loading...