Strongly component - algorithm

I am trying to write an algorithm that is given a graph G and 2 nodes 'x' and 'y'as input, which returns whether there is a cyclic path from 'x' to 'y'
Is it a good idea to find the strongly connected components first and then check if x and y belong to same strongly connected component. If they belong to different connected component say x belongs to C1 and y belongs to C2, then if there exists a path from C1 to C2, then we can say that there is a cyclic path from x to y.

Your idea with strongly connected components should work. Here is a graph and some code for you to experiment:
First, a digraph:
And it's adjacency lists representation:
13 vertices, 22 edges
0: 5 1
1:
2: 0 3
3: 5 2
4: 3 2
5: 4
6: 9 4 8 0
7: 6 9
8: 6
9: 11 10
10: 12
11: 4 12
12: 9
And it's strongly connected components:
7
6 8
9 10 11 12
0 2 3 4 5
1
Now, after with implementation for digraph and Kosaraju-Sharir
class StronglyConnectedComponents
{
private bool[] visited;
private int[] componentIds;
public int ComponentCount { get; private set; }
public StronglyConnectedComponents(DirectedGraph graph)
{
visited = new bool[graph.VertexCount];
componentIds = new int[graph.VertexCount];
var order = new GraphTraversal(graph).ReverseOrder();
var reversedGraph = graph.Reverse();
foreach (var vertex in order)
{
if (!visited[vertex])
{
DepthFirstSearch(reversedGraph, vertex);
ComponentCount++;
}
}
}
public int VertexComponentId(int vertex)
{
return componentIds[vertex];
}
public bool AreStronglyConnected(int source, int target)
{
return componentIds[source] == componentIds[target];
}
private void DepthFirstSearch(DirectedGraph graph, int vertex)
{
visited[vertex] = true;
componentIds[vertex] = ComponentCount;
foreach (var adjacent in graph.AdjacentTo(vertex))
{
if (!visited[adjacent])
{
DepthFirstSearch(graph, adjacent);
}
}
}
}
class GraphTraversal
{
private Stack<int> reversePostOrder;
private bool[] visited;
public GraphTraversal(DirectedGraph graph)
{
visited = new bool[graph.VertexCount];
reversePostOrder = new Stack<int>();
for (var vertex = 0; vertex < graph.VertexCount; vertex++)
{
if (!visited[vertex])
{
DepthFirstSearch(graph, vertex);
}
}
}
public IEnumerable<int> ReverseOrder()
{
return reversePostOrder;
}
private void DepthFirstSearch(DirectedGraph graph, int vertex)
{
visited[vertex] = true;
foreach (var adjacent in graph.AdjacentTo(vertex))
{
if (!visited[adjacent])
{
DepthFirstSearch(graph, adjacent);
}
}
reversePostOrder.Push(vertex);
}
}
class DirectedGraph
{
public int VertexCount { get; set; }
public int EdgeCount { get; set; } = 0;
private List<int>[] adjacencyLists;
public DirectedGraph(int vertexCount)
{
VertexCount = vertexCount;
InitializeAdjacencyLists(vertexCount);
}
public void AddEdge(int from, int to)
{
adjacencyLists[from].Add(to);
EdgeCount++;
}
public IEnumerable<int> AdjacentTo(int vertex)
{
return adjacencyLists[vertex];
}
public DirectedGraph Reverse()
{
var reversedGraph = new DirectedGraph(this.VertexCount);
for (var vertex = 0; vertex < this.VertexCount; vertex++)
{
foreach (var adjacent in this.AdjacentTo(vertex))
{
reversedGraph.AddEdge(adjacent, vertex);
}
}
return reversedGraph;
}
public override string ToString()
{
String graghString = VertexCount + " vertices, " + EdgeCount + " edges \n";
for (int vertex = 0; vertex < VertexCount; vertex++)
{
graghString += vertex + ": ";
foreach (var adjacnet in this.AdjacentTo(vertex))
{
graghString += adjacnet + " ";
}
graghString += "\n";
}
return graghString;
}
private void InitializeAdjacencyLists(int vertexCount)
{
adjacencyLists = new List<int>[vertexCount];
for (var vertex = 0; vertex < vertexCount; vertex++)
{
adjacencyLists[vertex] = new List<int>();
}
}
}
Queries like scc.AreStronglyConnected(2, 5) will tell if directed cycle between vertices exists. Runnable code is here.

I am assuming you want to count paths having 'x' or 'y' multiple times as well.
If 'x' and 'y' belong to same strongly connected component, there exists a path containing a cycle. (trivial, by definition of strongly connected component)
However, if they belong to different strongly connected components, 'y' should be reachable from 'x' and at least one component having a node on the path must have size more than one. (Take any cycle in that component and continue on the path)
Your solution will fail in case of a linear graph. There is no cycle, yet you can reach from 'x' to 'y' which belong to different strongly connected components.

Related

Algorithm to bucket set of numbers based on buckets sum

I have a set of items that I would like to bucket into N different buckets. Each item has a property associated with it (size) and I would like the sum of this property in each bucket to be roughly equal. What is the best way to determine this? Note the range of the size on the items is fairly large, in the data set I'm using the smallest size is 1 and the largest is 325,220.
Example:
Item A - size 5
Item B - size 10
Item C - size 8
Item D - size 16
Item E - size 7
If I wanted to group these into 3 buckets I would want
Bucket 1: A, B
Bucket 2: C, E
Bucket 3: D
I ended up implementing the complete greedy algorithm described in the paper linked by Joe Farrel. The full C# code I used is below:
public class Item
{
public int Id { get; }
public int Size { get; }
public Item(int id, int size)
{
Id = id;
size = size;
}
}
public class Partition
{
public int Index { get; }
public ImmutableList<Item> Items { get; } = ImmutableList<Item>.Empty;
public int Sum { get; }
public Partition(int index)
{
Index = index;
}
private Partition(int index, ImmutableList<Item> items, int sum)
{
Index = index;
Item = items;
Sum = sum;
}
public Partition Add(Item item) => new Partition(Index, Items.Add(item), Sum + item.Size);
public static double AverageDifference(ImmutableList<Partition> partitions)
{
var differences = new List<int>();
for (var i = 0; i < partitions.Count; i++)
{
var partition = partitions[i];
var otherPartitions = partitions.RemoveAt(i);
foreach (var otherPartition in otherPartitions)
{
differences.Add(Math.Abs(partition.Sum - otherPartition.Sum));
}
}
return differences.Average();
}
}
public class Node
{
public Item Item { get; set; }
public int Partition { get; set; }
public Node[] Children { get; set; }
}
private (Node tree, int totalSum) InitTree(IEnumerable<Item> items)
{
var root = new Node();
var totalSum = 0;
Node[] previousLevel = {root};
foreach (var item in items.OrderByDescending(i => i.Size))
{
totalSum += item.Size;
var currentLevel = new Node[_numPartitions];
for (var i = 0; i < _numPartitions; i++)
{
currentLevel[i] = new Node
{
Item = item,
Partition = i
};
}
foreach (var node in previousLevel)
{
node.Children = currentLevel;
}
previousLevel = currentLevel;
}
return (root, totalSum);
}
private ImmutableList<Partition> GetPartitions(Node tree, int totalSum)
{
var partitions = ImmutableList<Partition>.Empty;
for (var i = 0; i < _numPartitions; i++)
{
partitions = partitions.Add(new Partition(i));
}
return TraverseTree(tree, partitions, totalSum, double.MaxValue, ImmutableList<Partition>.Empty);
}
private ImmutableList<Partition> TraverseTree(Node node, ImmutableList<Partition> partitions, int totalSum, double bestDifference, ImmutableList<Partition> bestPartitions)
{
var currentPartitions = partitions;
if (node.Item != null) // skip root
{
// place item into its partition
var updatedPartition = currentPartitions[node.Partition].Add(node.Item);
currentPartitions = currentPartitions.SetItem(node.Partition, updatedPartition);
}
// if this is a leaf, partition is complete
if (node.Children == null)
{
return currentPartitions;
}
// terminate path if partition is sufficiently bad
var largestSum = currentPartitions.Max(p => p.Sum);
if (largestSum - (totalSum - largestSum) / (_numPartitions - 1) >= bestDifference)
{
return null;
}
// contintue to traverse tree in ascending partition size order
foreach (var partition in currentPartitions.OrderBy(p => p.Sum))
{
var nextNode = node.Children[partition.Index];
var nextPartitions = TraverseTree(nextNode, currentPartitions, totalSum, bestDifference, bestPartitions);
if (nextPartitions == null) // path was terminated
{
continue;
}
// if we hit a perfect parition set, return it
var nextDifference = Partition.AverageDifference(nextPartitions);
if (nextDifference <= 1)
{
return nextPartitions;
}
// hold on to the best partition
if (nextDifference < bestDifference)
{
bestDifference = nextDifference;
bestPartitions = nextPartitions;
}
}
return bestPartitions;
}
_numPartitions = 4
var items = GetItems()
var (tree, totalSum) = InitTree(items);
var partitions = GetPartitions(tree, totalSum);
My answer to this question on laying out pictures might be able to be adapted.
Pictures with height become items with size. Columns per page becomes buckets.
The algorithm has three parts: first-fit; greedy-swapping; and reverse sorting, some may be of more use than others with your data.

Randomised Path on graph - set length, no crossing, no dead ends

I am working on a game with a 8 wide 5 high grid. I have a 'snake' feature which needs to enter the grid and "walk" around for a set distance (20 for example). There are certain restrictions for the movement of the snake:
It needs go over the predetermined amount of blocks (20)
It cannot go over itself or double back (no dead ends)
Currently I am using a Randomised Depth First search, however I have found that it occasionally goes back over itself (crosses its own path) and am not sure if this is the best way to go about it.
Options considered: I have looked at using A*, but am struggling to figure out a good way to do it without a predetermined goal and the conditions above. I have also considered adding a heuristic to favour blocks that are not on the outside of the grid - but am not sure either of these will solve the issue at hand.
Any help is appreciated and I can add more detail or code if necessary:
public List<GridNode> RandomizedDepthFirst(int distance, GridNode startNode)
{
Stack<GridNode> frontier = new Stack<GridNode>();
frontier.Push(startNode);
List<GridNode> visited = new List<GridNode>();
visited.Add(startNode);
while (frontier.Count > 0 && visited.Count < distance)
{
GridNode current = frontier.Pop();
if (current.nodeState != GridNode.NodeState.VISITED)
{
current.nodeState = GridNode.NodeState.VISITED;
GridNode[] vals = current.FindNeighbours().ToArray();
List<GridNode> neighbours = new List<GridNode>();
foreach (GridNode g in vals.OrderBy(x => XMLReader.NextInt(0,0)))
{
neighbours.Add(g);
}
foreach (GridNode g in neighbours)
{
frontier.Push(g);
}
if (!visited.Contains(current))
{
visited.Add(current);
}
}
}
return visited;
}
An easy way to account for back tracking is using a recursive dfs search.
Consider the following graph:
And a java implementation of a dfs search, removing nodes from the path when backtracking (note the comments. Run it online here) :
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
public class Graph {
//all graph nodes
private Node[] nodes;
public Graph(int numberOfNodes) {
nodes = new Node[numberOfNodes];
//construct nodes
for (int i = 0; i < numberOfNodes; i++) {
nodes[i] = new Node(i);
}
}
// add edge from a to b
public Graph addEdge(int from, int to) {
nodes[from].addNeighbor(nodes[to]);
//unless unidirectional: //if a is connected to b
//than b should be connected to a
nodes[to].addNeighbor(nodes[from]);
return this; //makes it convenient to add multiple edges
}
//returns a list of path size of pathLength.
//if path not found : returns an empty list
public List<Node> dfs(int pathLength, int startNode) {
List<Node> path = new ArrayList<>(); //a list to hold all nodes in path
Stack<Node> frontier = new Stack<>();
frontier.push(nodes[startNode]);
dfs(pathLength, frontier, path);
return path;
}
private boolean dfs(int pathLength, Stack<Node> frontier, List<Node> path) {
if(frontier.size() < 1) {
return false; //stack is empty, no path found
}
Node current = frontier.pop();
current.setVisited(true);
path.add(current);
if(path.size() == pathLength) {
return true; //path size of pathLength found
}
System.out.println("testing node "+ current); //for testing
Collections.shuffle(current.getNeighbors()); //shuffle list of neighbours
for(Node node : current.getNeighbors()) {
if(! node.isVisited()) {
frontier.push(node);
if(dfs(pathLength, frontier, path)) { //if solution found
return true; //return true. continue otherwise
}
}
}
//if all neighbours tested and no solution found, current node
//is not part of the path
path.remove(current); // remove it
current.setVisited(false); //this accounts for loops: you may get to this node
//from another edge
return false;
}
public static void main(String[] args){
Graph graph = new Graph(9); //make graph
graph.addEdge(0, 4) //add edges
.addEdge(0, 1)
.addEdge(1, 2)
.addEdge(1, 4)
.addEdge(4, 3)
.addEdge(2, 3)
.addEdge(2, 5)
.addEdge(3, 5)
.addEdge(1, 6)
.addEdge(6, 7)
.addEdge(7, 8);
//print path with length of 6, starting with node 1
System.out.println( graph.dfs(6,1));
}
}
class Node {
private int id;
private boolean isVisited;
private List<Node>neighbors;
Node(int id){
this.id = id;
isVisited = false;
neighbors = new ArrayList<>();
}
List<Node> getNeighbors(){
return neighbors;
}
void addNeighbor(Node node) {
neighbors.add(node);
}
boolean isVisited() {
return isVisited;
}
void setVisited(boolean isVisited) {
this.isVisited = isVisited;
}
#Override
public String toString() {return String.valueOf(id);} //convenience
}
Output:
testing node 1
testing node 6
testing node 7
testing node 8
testing node 2
testing node 5
testing node 3
testing node 4
[1, 2, 5, 3, 4, 0]
Note that nodes 6,7,8 which are dead-end, are tested, but not included in the final path.

A* pathfinding trouble

I am using inScope Studio's Tower Defense tutorial as a scaffold for a game I'm making, and have set up a working A* pathfinder to get from start to finish, but am having trouble setting up dynamic pathfinding for attacking units.
When triggered, the unit should generate a path from its location to the target's location, but for some reason the pathfinding script fails to return a path. While debugging I noticed that the the algorithm isn't able to detect deduce the best path, and it just ends up putting all the nodes in the closed list.
Here is my A* script and pertinent code:
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public static class AStar
{
/// <summary>
/// A dictionary for all nodes in the game
/// </summary>
private static Dictionary<Point, Node> nodes;
/// <summary>
/// Creates a node for each tile in the game
/// </summary>
private static void CreateNodes()
{
//Instantiates the dicationary
nodes = new Dictionary<Point, Node>();
//Run throughm all the tiles in the game
foreach (TileScript tile in LevelManager.Instance.Tiles.Values)
{
//Adds the node to the node dictionary
nodes.Add(tile.GridPosition, new Node(tile));
}
}
/// <summary>
/// Generates a path with the A* algothithm
/// </summary>
/// <param name="start">The start of the path</param>
public static Stack<Node> GetPath(Point start, Point goal)
{
if (nodes == null) //If we don't have nodes then we need to create them
{
CreateNodes();
}
//Creates an open list to be used with the A* algorithm
HashSet<Node> openList = new HashSet<Node>();
//Creates an closed list to be used with the A* algorithm
HashSet<Node> closedList = new HashSet<Node>();
// 1,2,3
Stack<Node> finalPath = new Stack<Node>();
//Finds the start node and creates a reference to it called current node
Node currentNode = nodes[start];
//1. Adds the start node to the OpenList
openList.Add(currentNode);
while (openList.Count > 0)//Step 10
{
//2. Runs through all neighbors
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
Point neighbourPos = new Point(currentNode.GridPosition.X - x, currentNode.GridPosition.Y - y);
if (LevelManager.Instance.InBounds(neighbourPos) && LevelManager.Instance.Tiles[neighbourPos].Walkable && neighbourPos != currentNode.GridPosition)
{
//Sets the initial value of g to 0
int gCost = 0;
if (Math.Abs(x - y) == 1)//Check is we need to score 10
{
gCost = 10;
}
else //Scores 14 if we are diagonal
{
if(!ConnectedDiagonally(currentNode, nodes[neighbourPos]))
{
continue;
}
gCost = 14;
}
//3. Adds the neighbor to the open list
Node neighbour = nodes[neighbourPos];
Debug.Log (gCost);
if (openList.Contains(neighbour))
{
if (currentNode.G + gCost < neighbour.G)//Step 9.4
{
neighbour.CalcValues(currentNode, nodes[goal], gCost);
}
}
else if (!closedList.Contains(neighbour))//9.1
{
openList.Add(neighbour); //9.2
neighbour.CalcValues(currentNode, nodes[goal], gCost);//9.3
}
}
}
}
//5. & 8. Moves the current node from the open list to the closed list
openList.Remove(currentNode);
closedList.Add(currentNode);
if (openList.Count > 0)//STEP 7.
{
//Sorts the list by F value, and selects the first on the list
currentNode = openList.OrderBy(n => n.F).First();
}
Debug.Log ("currentNode: " + currentNode.GridPosition.X + ", " + currentNode.GridPosition.Y + "\ngoal: " + nodes[goal].GridPosition.X + ", " + nodes[goal].GridPosition.Y);
if (currentNode == nodes[goal])
{
while (currentNode.GridPosition != start)
{
finalPath.Push(currentNode);
currentNode = currentNode.Parent;
}
break;
}
}
return finalPath;
}
private static bool ConnectedDiagonally(Node currentNode, Node neighbor)
{
Point direction = neighbor.GridPosition - currentNode.GridPosition;
Point first = new Point (currentNode.GridPosition.X + direction.X, currentNode.GridPosition.Y + direction.Y);
Point second = new Point (currentNode.GridPosition.X, currentNode.GridPosition.Y + direction.Y);
if (LevelManager.Instance.InBounds (first) && !LevelManager.Instance.Tiles [first].Walkable)
{
return false;
}
if (LevelManager.Instance.InBounds (second) && !LevelManager.Instance.Tiles [second].Walkable) {
return false;
}
return true;
}
}
private void GeneratePathToTarget()
{
Point targetLocation = new Point (target.transform.parent.GetComponent<TileScript> ().GridPosition.X, target.transform.parent.GetComponent<TileScript> ().GridPosition.Y);
path = AStar.GetPath (this.GridPosition, targetLocation);
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Tower" && Attacker)
{
target = other.gameObject;
GeneratePathToTarget ();
}
}
Weirdly enough, I managed to get it working last week, but due to a massive github fail I'm having to rewrite everything.

Is it possible to design a tree where nodes have infinitely many children?

How can design a tree with lots (infinite number) of branches ?
Which data structure we should use to store child nodes ?
You can't actually store infinitely many children, since that won't fit into memory. However, you can store unboundedly many children - that is, you can make trees where each node can have any number of children with no fixed upper bound.
There are a few standard ways to do this. You could have each tree node store a list of all of its children (perhaps as a dynamic array or a linked list), which is often done with tries. For example, in C++, you might have something like this:
struct Node {
/* ... Data for the node goes here ... */
std::vector<Node*> children;
};
Alternatively, you could use the left-child/right-sibling representation, which represents a multiway tree as a binary tree. This is often used in priority queues like binomial heaps. For example:
struct Node {
/* ... data for the node ... */
Node* firstChild;
Node* nextSibling;
};
Hope this helps!
Yes! You can create a structure where children are materialized on demand (i.e. "lazy children"). In this case, the number of children can easily be functionally infinite.
Haskell is great for creating "functionally infinite" data structures, but since I don't know a whit of Haskell, here's a Python example instead:
class InfiniteTreeNode:
''' abstract base class for a tree node that has effectively infinite children '''
def __init__(self, data):
self.data = data
def getChild(self, n):
raise NotImplementedError
class PrimeSumNode(InfiniteTreeNode):
def getChild(self, n):
prime = getNthPrime(n) # hypothetical function to get the nth prime number
return PrimeSumNode(self.data + prime)
prime_root = PrimeSumNode(0)
print prime_root.getChild(3).getChild(4).data # would print 18: the 4th prime is 7 and the 5th prime is 11
Now, if you were to do a search of PrimeSumNode down to a depth of 2, you could find all the numbers that are sums of two primes (and if you can prove that this contains all even integers, you can win a big mathematical prize!).
Something like this
Node {
public String name;
Node n[];
}
Add nodes like so
public Node[] add_subnode(Node n[]) {
for (int i=0; i<n.length; i++) {
n[i] = new Node();
p("\n Enter name: ");
n[i].name = sc.next();
p("\n How many children for "+n[i].name+"?");
int children = sc.nextInt();
if (children > 0) {
Node x[] = new Node[children];
n[i].n = add_subnode(x);
}
}
return n;
}
Full working code:
class People {
private Scanner sc;
public People(Scanner sc) {
this.sc = sc;
}
public void main_thing() {
Node head = new Node();
head.name = "Head";
p("\n How many nodes do you want to add to Head: ");
int nodes = sc.nextInt();
head.n = new Node[nodes];
Node[] n = add_subnode(head.n);
print_nodes(head.n);
}
public Node[] add_subnode(Node n[]) {
for (int i=0; i<n.length; i++) {
n[i] = new Node();
p("\n Enter name: ");
n[i].name = sc.next();
p("\n How many children for "+n[i].name+"?");
int children = sc.nextInt();
if (children > 0) {
Node x[] = new Node[children];
n[i].n = add_subnode(x);
}
}
return n;
}
public void print_nodes(Node n[]) {
if (n!=null && n.length > 0) {
for (int i=0; i<n.length; i++) {
p("\n "+n[i].name);
print_nodes(n[i].n);
}
}
}
public static void p(String msg) {
System.out.print(msg);
}
}
class Node {
public String name;
Node n[];
}
I recommend you to use a Node class with a left child Node and right child Node and a parent Node.
public class Node
{
Node<T> parent;
Node<T> leftChild;
Node<T> rightChild;
T value;
Node(T val)
{
value = val;
leftChild = new Node<T>();
leftChild.parent = this;
rightChild = new Node<T>();
rightChild.parent = this;
}
You can set grand father and uncle and sibling like this.
Node<T> grandParent()
{
if(this.parent.parent != null)
{
return this.parent.parent;
}
else
return null;
}
Node<T> uncle()
{
if(this.grandParent() != null)
{
if(this.parent == this.grandParent().rightChild)
{
return this.grandParent().leftChild;
}
else
{
return this.grandParent().rightChild;
}
}
else
return null;
}
Node<T> sibling()
{
if(this.parent != null)
{
if(this == this.parent.rightChild)
{
return this.parent.leftChild;
}
else
{
return this.parent.rightChild;
}
}
else
return null;
}
And is impossible to have infinite child, at least you have infinite memory.
good luck !
Hope this will help you.

How do I find all paths in a sequence of edges in a fast way?

Let E be a given directed edge set. Suppose it is known that the edges in E can form a directed tree T with all the nodes (except the root node) has only 1 in-degree. The problem is how to efficiently traverse the edge set E, in order to find all the paths in T?
For example, Given a directed edge set E={(1,2),(1,5),(5,6),(1,4),(2,3)}. We know that such a set E can generate a directed tree T with only 1 in-degree (except the root node). Is there any fast method to traverse the edge set E, in order to find all the paths as follows:
Path1 = {(1,2),(2,3)}
Path2 = {(1,4)}
Path3 = {(1,5),(5,6)}
By the way, suppose the number of edges in E is |E|, is there complexity bound to find all the paths?
I have not worked on this kind of problems earlier. So just tried out a simple solution. Check this out.
public class PathFinder
{
private static Dictionary<string, Path> pathsDictionary = new Dictionary<string, Path>();
private static List<Path> newPaths = new List<Path>();
public static Dictionary<string, Path> GetBestPaths(List<Edge> edgesInTree)
{
foreach (var e in edgesInTree)
{
SetNewPathsToAdd(e);
UpdatePaths();
}
return pathsDictionary;
}
private static void SetNewPathsToAdd(Edge currentEdge)
{
newPaths.Clear();
newPaths.Add(new Path(new List<Edge> { currentEdge }));
if (!pathsDictionary.ContainsKey(currentEdge.PathKey()))
{
var pathKeys = pathsDictionary.Keys.Where(c => c.Split(",".ToCharArray())[1] == currentEdge.StartPoint.ToString()).ToList();
pathKeys.ForEach(key => { var newPath = new Path(pathsDictionary[key].ConnectedEdges); newPath.ConnectedEdges.Add(currentEdge); newPaths.Add(newPath); });
pathKeys = pathsDictionary.Keys.Where(c => c.Split(",".ToCharArray())[0] == currentEdge.EndPoint.ToString()).ToList();
pathKeys.ForEach(key => { var newPath = new Path(pathsDictionary[key].ConnectedEdges); newPath.ConnectedEdges.Insert(0, currentEdge); newPaths.Add(newPath); });
}
}
private static void UpdatePaths()
{
Path oldPath = null;
foreach (Path newPath in newPaths)
{
if (!pathsDictionary.ContainsKey(newPath.PathKey()))
pathsDictionary.Add(newPath.PathKey(), newPath);
else
{
oldPath = pathsDictionary[newPath.PathKey()];
if (newPath.PathWeights < oldPath.PathWeights)
pathsDictionary[newPath.PathKey()] = newPath;
}
}
}
}
public static class Extensions
{
public static bool IsNullOrEmpty(this IEnumerable<object> collection) { return collection == null || collection.Count() > 0; }
public static string PathKey(this ILine line) { return string.Format("{0},{1}", line.StartPoint, line.EndPoint); }
}
public interface ILine
{
int StartPoint { get; }
int EndPoint { get; }
}
public class Edge :ILine
{
public int StartPoint { get; set; }
public int EndPoint { get; set; }
public Edge(int startPoint, int endPoint)
{
this.EndPoint = endPoint;
this.StartPoint = startPoint;
}
}
public class Path :ILine
{
private List<Edge> connectedEdges = new List<Edge>();
public Path(List<Edge> edges) { this.connectedEdges = edges; }
public int StartPoint { get { return this.IsValid ? this.connectedEdges.First().StartPoint : 0; } }
public int EndPoint { get { return this.IsValid ? this.connectedEdges.Last().EndPoint : 0; } }
public bool IsValid { get { return this.EdgeCount > 0; } }
public int EdgeCount { get { return this.connectedEdges.Count; } }
// For now as no weights logics are defined
public int PathWeights { get { return this.EdgeCount; } }
public List<Edge> ConnectedEdges { get { return this.connectedEdges; } }
}
I think DFS(Depth First Search) should suit your requirements. Have a look at it here - Depth First Search - Wikipedia. You can tailor it to print the paths in the format that you require. As regards the complexity, since every node in your tree has in-degree one , the number of edges for your tree is bounded as - |E| = O(|V|). Since DFS operates with a complexity of O(|V|+|E|), your overall complexity comes out to be O(|V|).
I did this question as a part of a my assignment. The gentleman above has correctly pointed out to use pathID. You must visit each edge atleast once hence the complexity bound is O(V+E) but for tree E=O(V) therefore the complexity is O(v). I will give you a glimpse since the details are bit involved -
you will label each path with a unique ID and the path are alloted IDs in the incremental values such as 0,1,2.... A pathID of a path is the sum of weights of the edges on the path. So using DFS allocate weights to the path. You may begin by using 0 for edges until you encounter your first path and then you keep adding 1 and so on. You will also have to argue the correctness and properly allocate the weights. DFS will do the trick.

Resources