Incorrect output in Dijkstra's implementation - algorithm

I am trying to implement Dijkstra's algorithm using adjacency list and priority queue but getting incorrect output for some of the vertices. Since there is no decreaseKey method in inbuilt priority queue in Java I am adding the new vertex (with updated distance from source). Can anyone advise where am I mistaken ? My code is :
class Graph3 {
private int V;
private ArrayList<Integer> adj [];
Map<String, Integer> weight; //for O(1) lookup of edge weight
PriorityQueue<Vertex> minHeap;
int d [];
int p[];
boolean visited [];
Graph3(int n) {
this.V = n;
adj = new ArrayList[n];
for(int i=0; i<n; i++) {
adj[i] = new ArrayList<Integer>();
}
weight = new HashMap<String, Integer> ();
minHeap = new PriorityQueue<Vertex>(n, new Vertex());
visited = new boolean[n];
Arrays.fill(visited, false);
p = new int[n];
Arrays.fill(p, -1);
d = new int[n];
Arrays.fill(d,Integer.MAX_VALUE);
}
public void addEdge(int a, int b, int w) {
adj[a].add(b);
weight.put(a+","+b,w); //cost of edge(a,b)
}
public void calculateShortest(int source) {
d[source] = 0;
visited[source] = true;
for(int i=0; i<V; i++) minHeap.offer(new Vertex(i,d[i]));
while(!minHeap.isEmpty()) {
Vertex u = minHeap.poll();
relaxEdges(u); //relax all outgoing edges of u
}
for(int i=0; i<d.length; i++) {
System.out.println("Shortest path from "+source+" to vertex "+i+" = "+d[i]);
}
}
public void relaxEdges(Vertex u) {
for(int i: adj[u.getName()]) {
if(!visited[i]) {
int alt = d[u.getName()] + weight.get(u.getName()+","+i);
if(d[i] > alt) {
d[i] = alt;
Vertex temp = new Vertex(i,d[i]);
minHeap.offer(temp);
p[i] = u.getName();
visited[i] = true;
}
}
}
}
}
//to be used for binding every vertex with dval for use in PQ
class Vertex implements Comparator<Vertex> {
int name;
int dval; //current min distance from source
public Vertex() {
}
public Vertex(int name, int dval) {
this.name = name;
this.dval = dval;
}
public int getName() {
return name;
}
public void setName(int name) {
this.name = name;
}
public int getDval() {
return dval;
}
public void setDval(int dval) {
this.dval = dval;
}
public int compare(Vertex a, Vertex b) {
return (a.dval - b.dval);
}
}
public class DijkstraShortestPath {
public static void main(String args []) {
Graph3 g = new Graph3(9);
g.addEdge(0, 1, 4);
g.addEdge(0, 7, 8);
g.addEdge(1, 2, 8);
g.addEdge(1, 7, 11);
g.addEdge(2, 3, 7);
g.addEdge(2, 8, 2);
g.addEdge(2, 5, 4);
g.addEdge(3, 4, 9);
g.addEdge(3, 5, 14);
g.addEdge(4, 5, 10);
g.addEdge(5, 6, 2);
g.addEdge(6, 7, 1);
g.addEdge(6, 8, 6);
g.addEdge(7, 8, 7);
g.calculateShortest(0);
}
}
**My Output :**
Shortest path from 0 to vertex 0 = 0
Shortest path from 0 to vertex 1 = 4
Shortest path from 0 to vertex 2 = 12
Shortest path from 0 to vertex 3 = 19
Shortest path from 0 to vertex 4 = 28
Shortest path from 0 to vertex 5 = 16
Shortest path from 0 to vertex 6 = 18
Shortest path from 0 to vertex 7 = 8
Shortest path from 0 to vertex 8 = 15
**Correct Output :**
Shortest path from 0 to vertex 0 = 0
Shortest path from 0 to vertex 1 = 4
Shortest path from 0 to vertex 2 = 12
Shortest path from 0 to vertex 3 = 19
Shortest path from 0 to vertex 4 = 21
Shortest path from 0 to vertex 5 = 11
Shortest path from 0 to vertex 6 = 9
Shortest path from 0 to vertex 7 = 8
Shortest path from 0 to vertex 8 = 14

Something that is off is that you set visited[i] = true for all neighboring nodes that get updated in relaxEdges. Dijkstra's algorithm always only sets the currently processed node to visited, not the neighbors. I would guess that this is why you get incorrect output. Delete this line and instead add visited[u.getName()] = true in the while loop.
Since you add nodes multiple times to the queue, you should also directly test against visited[u.getName()] in the while-loop so nodes do not get processed multiple times.
Then, you assign to p[i], but never use it.
And lastly, I advice to have an Edge class because representing edges as string-concatenated integers sure is clunky.

Related

Minimum Cost Path with Left, Right, Bottom and Up moves allowed

Problem Statement:
Given a square grid of size N, each cell of which contains integer cost which represents a cost to traverse through that cell, we need to find a path from top left cell to bottom right cell by which the total cost incurred is minimum.
From the cell (i,j) we can go (i,j-1), (i, j+1), (i-1, j), (i+1, j).
Note: It is assumed that negative cost cycles do not exist in the input matrix.
Below is the code that I have written:
class Coordinate {
int x;
int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Coordinate other = (Coordinate) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
public class MinCostPath {
public static int minimumCostPath(int[][] grid) {
int R = grid.length;
int C = grid[0].length;
int[][] dist = new int[R][C];
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
dist[i][j] = Integer.MAX_VALUE;
}
}
dist[0][0] = grid[0][0];
Queue<Coordinate> q = new LinkedList<>();
q.add(new Coordinate(0, 0));
int[] x = { -1, 1, 0, 0 };
int[] y = { 0, 0, 1, -1 };
while (!q.isEmpty()) {
Coordinate current = q.poll();
for (int i = 0; i < 4; i++) {
int xi = current.getX() + x[i];
int yi = current.getY() + y[i];
if (isSafe(xi, yi, R, C)) {
if (dist[xi][yi] > dist[current.getX()][current.getY()] + grid[xi][yi]) {
dist[xi][yi] = dist[current.getX()][current.getY()] + grid[xi][yi];
Coordinate c = new Coordinate(xi, yi);
if (!q.contains(c))
q.add(c);
}
}
}
}
return dist[R - 1][C - 1];
}
private static boolean isSafe(int xi, int yi, int r, int c) {
return (xi >= 0) && (xi < r) && (yi >= 0) && (yi < c);
}
public static void main(String[] args) {
int[][] grid = { { 9, 4, 9, 9 }, { 6, 7, 6, 4 }, { 8, 3, 3, 7 }, { 7, 4, 9, 10 } };
System.out.println(minimumCostPath(grid));
}
}
It gives 'Runtime Error:Time Limit Exceeded' Error
Below is an article from geeksforgeeks that has the solution.
Minimum Cost Path Problem
What I am not able to understand is why my code is giving 'Time Limit Exceeded' Error while the solution mentioned in the article is working. To my understanding, both the solutions are doing exactly the same thing.
Please help me understand the difference and what optimization is needed in the code that I have written. Thanks in Advance.
It seems from your implementation that you are trying to use Breadth First Search instead of Dijkstra which is the right approach to solve this.
You need to use a priority queue and a map to trace your path.
Also for BFS typically you don't need to do if (! q.contains(node)) that actually unnecessarily consumes time.
what optimization is needed in the code
The problem needs to be reformulated so you can apply the Dijkstra algorithm ( https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm )
That algorithm assumes the links are costed, rather than the nodes ( cells ). Consider two adjacent cells with traversal costs c and d. Travelling from the first to the second adds cost d. Travelling from the second to the first adds cost c. So you can connect the two cells with two unidirectional links of cost c and d. The Dijkstra algorithm will give you the correct cost when the entire path is travelled, minus the the traversal cost of the first cell - which is a constant and can therefor be ignored when finding the optimal path.
I use the boost graph implementation of Dijkstra, which is fast and well tested ( https://www.boost.org/doc/libs/1_76_0/libs/graph/doc/dijkstra_shortest_paths.html ). The API is a challenge if you haven't used the boost library before, so I use a C++ style wrapper to simplify coding ( https://github.com/JamesBremner/PathFinder )
Here is the output from PathFinder on the sample problem you posted
C:\Users\James\code\PathFinder\bin>mazes ..\dat\vivekkumar.txt
Mazes
cellcosts
s9 4 9 9
6 7 6 4
8 3 3 7
7 4 9 e10
4 by 4
0 -> 1 -> 5 -> 9 -> 10 -> 11 -> 15 ->
+---+---+---+---+
| s * |
+ + + + +
| * |
+ + + + +
| * * * |
+ + + + +
| e |
+---+---+---+---+

Bridge in a graph that makes the graph disconnected

I am working on programming where I need to find the articulation points of a graph (nodes such that removing any of them makes the graph disconnected)
For example, I have these links:
Example 1
[[0,1], [0,2], [1,3], [2,3], [5,6], [3,4]]
The answer should be [2,3,5], because removing these nodes makes the graph disconnected.
Explanation:
If I remove node 2 here, the graph becomes 2 parts 0,1,3,4 and 5,6
If I remove node 3 here, the graph becomes 2 parts 0,1,2,5,6 and 4
If I remove node 5 here, the graph becomes 2 parts 0,1,2,3,4 and 6
Example 2:
[[1,2], [2,3], [3,4], [4,5], [6,3]]
The output should be: [2, 3, 4]
Explanation:
If I remove node 2 here, the graph becomes 2 parts 1, and 3,4,5,6
If I remove node 3 here, the graph becomes 3 parts 1,2 and 6 and 4,5
If I remove node 4 here, the graph becomes 2 parts 1,2,3,6 and 5
How to achieve this in a Java program?
import static java.lang.Math.min;
import java.util.ArrayList;
import java.util.List;
public class ArticulationPointsAdjacencyList {
private int n, id, rootNodeOutcomingEdgeCount;
private boolean solved;
private int[] low, ids;
private boolean[] visited, isArticulationPoint;
private List<List<Integer>> graph;
public ArticulationPointsAdjacencyList(List<List<Integer>> graph, int n) {
if (graph == null || n <= 0 || graph.size() != n) throw new IllegalArgumentException();
this.graph = graph;
this.n = n;
}
// Returns the indexes for all articulation points in the graph even if the
// graph is not fully connected.
public boolean[] findArticulationPoints() {
if (solved) return isArticulationPoint;
id = 0;
low = new int[n]; // Low link values
ids = new int[n]; // Nodes ids
visited = new boolean[n];
isArticulationPoint = new boolean[n];
for (int i = 0; i < n; i++) {
if (!visited[i]) {
rootNodeOutcomingEdgeCount = 0;
dfs(i, i, -1);
isArticulationPoint[i] = (rootNodeOutcomingEdgeCount > 1);
}
}
solved = true;
return isArticulationPoint;
}
private void dfs(int root, int at, int parent) {
if (parent == root) rootNodeOutcomingEdgeCount++;
visited[at] = true;
low[at] = ids[at] = id++;
List<Integer> edges = graph.get(at);
for (Integer to : edges) {
if (to == parent) continue;
if (!visited[to]) {
dfs(root, to, at);
low[at] = min(low[at], low[to]);
if (ids[at] <= low[to]) {
isArticulationPoint[at] = true;
}
} else {
low[at] = min(low[at], ids[to]);
}
}
}
/* Graph helpers */
// Initialize a graph with 'n' nodes.
public static List<List<Integer>> createGraph(int n) {
List<List<Integer>> graph = new ArrayList<>(n);
for (int i = 0; i < n; i++) graph.add(new ArrayList<>());
return graph;
}
// Add an undirected edge to a graph.
public static void addEdge(List<List<Integer>> graph, int from, int to) {
graph.get(from).add(to);
graph.get(to).add(from);
}
/* Example usage: */
public static void main(String[] args) {
testExample2();
}
private static void testExample1() {
int n = 7;
List < List < Integer >> graph = createGraph (n);
addEdge (graph, 0, 1);
addEdge (graph, 0, 2);
addEdge (graph, 1, 3);
addEdge (graph, 2, 3);
addEdge (graph, 2, 5);
addEdge (graph, 5, 6);
addEdge (graph, 3, 4);
ArticulationPointsAdjacencyList solver = new ArticulationPointsAdjacencyList(graph, n);
boolean[] isArticulationPoint = solver.findArticulationPoints();
// Prints:
// Node 2 is an articulation
// Node 3 is an articulation
// Node 5 is an articulation
for (int i = 0; i < n; i++)
if (isArticulationPoint[i]) System.out.printf("Node %d is an articulation\n", i);
}
private static void testExample2() {
int n = 7;
List < List < Integer >> graph = createGraph (n);
addEdge (graph, 1, 2);
addEdge (graph, 2, 3);
addEdge (graph, 3, 4);
addEdge (graph, 3, 6);
addEdge (graph, 4, 5);
ArticulationPointsAdjacencyList solver = new ArticulationPointsAdjacencyList(graph, n);
boolean[] isArticulationPoint = solver.findArticulationPoints();
// Prints:
// Node 2 is an articulation
// Node 3 is an articulation
// Node 4 is an articulation
for (int i = 0; i < n; i++)
if (isArticulationPoint[i]) System.out.printf("Node %d is an articulation\n", i);
}
}
Reference: https://github.com/williamfiset/Algorithms/blob/master/com/williamfiset/algorithms/graphtheory/ArticulationPointsAdjacencyList.java
There are different algorithms used to find the nodes such that if removed they make the graph disconnected (called articulation points).
Here I explain one of them and I provide some code that implements it:
Tarjan Algorithm
Given a graph we want to find all the such that if is removed from the graph become disconnected
The first observation is that the a (weak) connected component in a directed graph is equal to a connected component in the same graph, but where the edges are undirected. So for simplicity we consider as an undirected graph.
Algorithm description
On the graph we run a pre-order Depth First Search (DFS) visit where for any node we assign 2 values, let's call it pre and low. pre represent the instant when the node is visited and low the instant of the lowest reachable node from .
The visit works in this way:
At every step of the visit both pre and low of are set to the next value of pre. Then if we find that a cycle is being closed we set low to pre of the start cycle node. low value is transmitted to parent through DFS backtracking.
When the DFS finish for every couple of nodes such that and are neighbor and low value of is greater or equal to the pre value of then is an articulation point.
For this there is an exception: the root of the DFS spanning tree is an articulation point only if it has more than 1 children
Example
(In the graph P obviously means pre and L means low)
At first pre and low of every vertex are set to a default value (let's say -1)
We start from node 0 and set his pre and low
We go to node 1 and set his pre and low
We can go to 2 or 3, we decide to go to 2 and set his pre and low
We can go to 4 or 5, we decide to go to 4 and set his pre and low
We go to 3 and set his pre and low
We see that 1 is alredy visited; that means it is a cycle, so we update low of 3 to pre of 1
Through backtrack we return to 4 and update his low value
Through backtrack we return to 2 and update his low value
Now we go to 5 and set his pre and low
Through backtrack we return to 2, but there's nothing to do.
We returned from 5 so his low value is fixed and is greater than pre value of 2; so 2 is an articulation point
Through backtrack we return to 1, and there's nothing to do.
We returned from 2 so his low value is fixed and is equal to the pre value of 1; so 1 is an articulation point
Through backtrack we return to 0, but there's nothing to do.
We returned from 1 so his low value is fixed and is greater than pre value of 0; but 0 is the root and has only one child; so it isn't an articulation point
So we have found the answer: [1, 2]
Code
Here is a simple really easy to understand snippet of code (C++) extracted from Competitive Programming Handbook by S. Halim and F. Halim and modified by me.
It is not very adapt to "real word application" (for example because it uses global variables) but it is ok for competitive programming and explaining due to his brevity and clearness.
const int UNVISITED = -1;
vector<int> dfs_low;
vector<int> dfs_pre;
int dfsNumberCounter;
int rootChildren;
vector<vector<int>> AdjList;
vector<int> articulation_vertex;
// This function is the DFS that implement Tarjan algoritm
void articulationPoint(int u) {
dfs_low[u] = dfs_pre[u] = dfsNumberCounter++; // dfs_low[u] <= dfs_pre[u]
for (int j = 0; j < (int)AdjList[u].size(); j++) {
int v = AdjList[u][j];
if (dfs_pre[v] == UNVISITED) { // a tree edge
dfs_parent[v] = u;
if (u == dfsRoot) rootChildren++; // special case if u is a root
articulationPoint(v);
if (dfs_low[v] >= dfs_pre[u]) // for articulation point
articulation_vertex[u] = true; // store this information first
dfs_low[u] = min(dfs_low[u], dfs_low[v]); // update dfs_low[u]
}
else if (v != dfs_parent[u]) // a back edge and not direct cycle
dfs_low[u] = min(dfs_low[u], dfs_pre[v]); // update dfs_low[u]
} }
// Some driver code
int main() {
... //Init of variables and store of the graph inside AdjList is omitted
... // V is the number of nodes
dfsNumberCounter = 0;
dfs_pre.assign(V, UNVISITED);
dfs_low.assign(V, 0);
dfs_parent.assign(V, 0);
articulation_vertex.assign(V, 0);
rootChildren = 0;
articulationPoint(0);
if (root_children > 1) {
articulation_vertex[0] = false;
}
printf("Articulation Points:\n");
for (int i = 0; i < V; i++)
if (articulation_vertex[i])
printf(" Vertex %d\n", i);
}

Converging maze: Largest cycle

This question was asked in one interview and i am still hunting for the best solution.
You are given a maze with N cells. Each cell may have multiple entry points but not more than one exit
(ie. entry/exit points are unidirectional doors like valves).
The cells are named with an integer value from 0
to N-1.
You need to find the the length of the largest cycle in the maze. Return -1 if there are no cycles.
INPUT FORMAT
First line has the number of cells N
Second line has list of N values of the edge[] array. edge[i] contains the cell number that
can be reached from of cell ‘i’ in one step. edge[i] is -1 if the ‘i’th cell doesn’t have an exit.
OUTPUT FORMAT
length of the largest cycle.
Sample input:
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
Sample output
6
I have already tried to do this with DFS to find all possible cycles and print the largest cycle size.
Please let me know if there is any better solution for the same.
Given a node in the graph, there's a unique maximal path starting from it (since there's at most one exit from any node). It may or may not cycle.
It's easy to find the eventual cycle length starting from a node: keep following exit nodes, recording nodes in a set along the path. Stop when you either find no exit node, or you're about to visit a previously visited node. If there's no exit node there's no cycle, and otherwise you can find the cycle length by starting at the previously visited node, and re-trace the cycle. [You could also use Floyd's algorithm here which would require O(1) rather than O(N) storage, but we're going to use O(N) storage anyway in the next step].
Using this, one can find the maximum cycle in O(N) time: repeat the above algorithm for each node in the graph, but cache results (storing -1 if there's no cycle found). You have to be careful to stop the cycle-finding above if you find a previously cached result along your path, and once you've found a result for a node, you must cache the result for all nodes along the path until you find a node who's result is already cached. The size of the largest cycle is the value of the largest cached value.
This is O(N) runtime: each edge (of which there's at most N) is followed at most 3 times in the graph, and the cache is updated exactly once for each node in the graph. It's uses O(N) additional storage.
public static int solution(int arr[])
{
ArrayList<Integer> sum = new ArrayList<>();
for(int i = 0; i < arr.length; i ++)
{
ArrayList<Integer> path = new ArrayList<>();
int j = i;
int tempSum = 0;
while(arr[j]<arr.length && arr[j]!=i && arr[j]!=-1 && !path.contains(j))
{
path.add(j);
tempSum+=j;
j=arr[j];
if(arr[j]==i)
{
tempSum+=j;
break;
}
}
if(j<arr.length && i == arr[j])
sum.add(tempSum);
}
if(sum.isEmpty())
return -1;
return Collections.max(sum);
}
Here is an implementation in JavaScript. I didn't use any fancy features of JavaScript, so the algorithm can be readily seen from the code. On the other hand, it does need ES6 support to run (forget IE):
function largestCycle(edges) {
var result, visitedFrom, startCell, cell, cells;
result = [];
visitedFrom = Array(edges.length).fill(-1);
for (startCell = 0; startCell < edges.length; startCell++) {
cells = [];
for (cell=startCell; cell>-1 && visitedFrom[cell]===-1; cell = edges[cell]) {
visitedFrom[cell] = startCell;
cells.push(cell);
}
if (cell > -1 && visitedFrom[cell] === startCell) {
cells = cells.slice(cells.indexOf(cell));
if (cells.length > result.length) result = cells;
}
}
return result;
}
// Snippet I/O
var input = document.querySelector('textarea');
var output = document.querySelector('span');
(input.oninput = function () {
// Get input as array of numbers
var edges = input.value.trim().split(/\s+/).map(Number);
// Apply algorithm
var cycle = largestCycle(edges);
// Output result
output.textContent = cycle.length + ': ' + JSON.stringify(cycle);
})(); // Execute also at page load
Input:<br>
<textarea style="width:100%">4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21</textarea><br>
Greatest Cycle: <span></span>
This runs in O(n). Even though the outer loop has both a nested loop and an expression that iterates over an array (using slice and indexOf), these sub-iterations are only executed once per cell, so in total this is still O(n).
The function does not only return the cycle size, but also the array containing the list of cells that belong to that cycle. It is a small overhead, but allows to better verify the result.
Python implementation of the solution suggested by trincot.
Explanation:
iterate over each node
For each node use the indices to navigate to the next node. Eg(1st iteration : outer for loop)
from 0th index we can reach 4 , from 4th index we can reach 13 , and from 13th index we can reach 11, and so on till we reach the visited node again in our case 0,
viola , we have found the first cycle.
check if visitedFrom[cell] == startCell i.e. 0 add it to the result array.
repeat for next node (step1)
Code
def largestCycle(edges):
result = []
visitedFrom = [-1] * len(edges)
for startCell in range(0, len(edges)):
cells = []
cell = startCell
while cell > -1 and visitedFrom[cell] == -1:
visitedFrom[cell] = startCell
cells.append(cell)
cell = edges[cell]
if cell > -1 and visitedFrom[cell] == startCell:
cells_idx = cells.index(cell)
cells = cells[cells_idx:]
if len(cells) > len(result):
result = cells
return result,len(result)
size = 23
edges = [4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21]
largestCycle(edges)
Using Prims algorithm to Find max Cycle in the Node
n = int(input())
v = n
e = v+1
arr = [int(i) for i in input().split()]
graph = [[0 for _ in range(n)] for _ in range(n)]
for i in range(0, len(arr)):
graph[i][arr[i]] = 1
for i in graph:
print(i)
def min_ind(wieight, visied):
min_ = -1
ind = -1
for i in range(v):
if(wieight[i] > min_ and visied[i] == False):
min_ = wieight[i]
ind = i
return ind
def printPath(parent, i):
res = []
while(parent[i] != -1):
res.append(i)
i = parent[i]
res.append(i)
return res[::-1]
# Dijkstra
visited = [False for _ in range(v)]
wieight = [0 for _ in range(v)]
parent = [-1 for i in range(v)]
wieight[0] = 0
path = []
for _ in range(v):
u = min_ind(wieight, visited)
if(u == -1):
continue
visited[u] = True
for i in range(v):
if(graph[u][i] > 0 and visited[i] == False):
if(wieight[i] < graph[u][i]):
wieight[i] = graph[u][i]
parent[i] = u
maximum = 0
for i in range(0, len(wieight)):
print("No:", i, " Weight:", wieight[i], " Path:", end=" ")
path = (printPath(parent, i))
maximum = max(maximum, len(path))
print(path, end=" ")
print()
print("Longest Cycle: ", maximum)
here is the solution for the problem but input format is not actually the same.
Here is the input format:
test cases: N
size of array: M
array elements: 1<=a(i)<=M-1 where 0<=i<=M-1
index to which last index points: C
In this problem, we have to count the cells in the largest cycle, here is the code:
class countLargestCycleMaze {
static vertex[] cells;
static class vertex {
int name;
neighbor list;
public vertex(int v, neighbor nb) {
this.name = v;
this.list = nb;
}
}
static class neighbor {
int vnum;
neighbor next;
public neighbor(int v, neighbor nb) {
this.vnum = v;
this.next = nb;
}
}
static int dfs(int v, int m) {
neighbor tmp = cells[v].list;
int c = 0;
while (tmp.vnum != m)
tmp = cells[tmp.vnum].list;
tmp = cells[tmp.vnum].list;
while (tmp.vnum != m) {
tmp = cells[tmp.vnum].list;
c++;
}
return c;
}
public static void main(String[] args) throws java.lang.Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int i, j, n, m, c;
n = Integer.parseInt(br.readLine());
while (n-- > 0) {
m = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
c = Integer.parseInt(br.readLine());
if (c == 0) {
System.out.println("0");
continue;
}
cells = new vertex[m + 1];
for (i = 0; i < m; i++) {
int num = Integer.parseInt(st.nextToken());
cells[i] = new vertex(num, null);
cells[i].list = new neighbor(num, cells[i].list);
}
cells[m] = new vertex(c, null);
cells[m].list = new neighbor(c, cells[m].list);
System.out.println(dfs(0, c));
}
} catch (Exception e) {}
}
}
public class LargestCycleInGraph {
public static int checkCycle(int []cell , int size , int start) {
Set<Integer> set = new HashSet<>();
set.add(start);
for(int i = start ;i< size;i++) {
if( !set.contains(cell[i]) && cell[i] != -1) {
set.add( cell[i] );
}
else return set.size() + 1; // 1 for again come to cycle node
}
return -1;
}
public static int findLargestCycle(int []cell , int size) {
int max = -1;
for(int i =0;i<size;i++) {
//if you want to find sum of largest cycle return "Set" rather than its size and check for max sum
int cyc = checkCycle(cell , size , i);
if(max < cyc)
max = cyc;
}
return max;
}
public static void main(String[] args) {
int size = 23;
int []cell = {4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21};
int largestCycle = findLargestCycle(cell , size);
System.out.println("Largest cycle Length " +largestCycle);
}
}
def main():
size = int(input())
cell = input().split()
for i in range(0, len(cell)):
cell[i] = int(cell[i])
m = -1
for i in range(0, 23):
if m < check_cycle(cell, i):
m = check_cycle(cell, i)
print("Largest cycle is made of", m, "nodes")
def check_cycle(cell, start):
i = start
if i in cell:
cycle = [i]
j = i
while 1:
for k in cycle:
if cycle.count(k) >= 2:
if cycle[0] == cycle[-1]:
return len(cycle)-1
else:
return 0
else:
cycle.append(cell[j])
j = cell[j]
else:
return 0
main()
Here is my attempt, to traverse each node of the graph:-
#include <stdio.h>
int findingLargestCycle(int noOfInputs, int *edges){
int largestCycle = 0;
for(int i=0; i<noOfInputs; i++){
int currentEdge = edges[i];
int count = currentEdge;
int nextEdge = edges[currentEdge];
int n = 0;
while(currentEdge != nextEdge && n<noOfInputs+1){
if(nextEdge == -1 || currentEdge == -1){
count = 0;
break;
}
if(nextEdge != currentEdge){
count += nextEdge;
}
nextEdge = edges[nextEdge];
n++;
}
if(count > largestCycle && n != noOfInputs+1){
largestCycle = count;
}
}
return largestCycle;
}
int main(){
int testCases;
scanf("%d", &testCases);
int numberOfInputs;
scanf("%d", &numberOfInputs);
int edges[numberOfInputs];
for(int i=0; i<numberOfInputs; i++){
scanf("%d", &edges[i]);
}
printf("%d", findingLargestCycle(numberOfInputs, &edges[0]));
}
O(n) time complexity solution each node is visited only after checking it's visited before or not, so each node is visited only once.
O(n) space complexity ([n]:stack space max + [2*n]:two map used max size)
To observe: there is always a unique path between two nodes(check with any test case), because of condition, only one exit from each node.
C++ code:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
//res stores result
int res = 0;
//visit to check in before visiting the node, to stop repeat visiting
unordered_map<int,bool> visit;
void dfs(vector<int> & a, unordered_map<int,int> &mp, int i, int k){
if(visit.find(i) != visit.end())
return;
if(a[i] == -1){
visit[i] = true;
return;
}
if(mp.find(i) != mp.end()){
res = max(res, k-mp[i]);
visit[i] = true;
return;
}
mp[i] = k;
dfs(a, mp, a[i], k+1);
visit[i] = true;
}
int main() {
int n;
cin>>n;
vector<int> a(n,0);
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++){
if(visit.find(i) == visit.end()){
unordered_map<int,int> mp;
dfs(a, mp, i, 0);
}
}
cout<<res<<endl;
return 0;
}
Solution in C++
#include <bits/stdc++.h>
using namespace std;
bool isCycle(vector<int> arr, int curr, vector<bool> &visited, vector<int> &path)
{
if (curr == -1)
{
return false;
}
if (visited[curr])
{
return true;
}
visited[curr] = true;
path.emplace_back(curr);
if (isCycle(arr, arr[curr], visited, path))
return true;
return false;
}
int largestSumCycle(vector<int> arr)
{
int n = arr.size();
int sum = INT_MIN;
vector<bool> visited(n, false);
for (int i = 0; i < n; i++)
{
visited[i] = true;
vector<int> path;
if (isCycle(arr, arr[i], visited, path))
sum = max(sum, accumulate(path.begin(), path.end(), 0));
visited[i] = false;
}
if (sum == INT_MIN)
return -1;
return sum;
}
This is a common question in interviews, in the same interview they asked this question also for the same details in question.
Q: find the NEAREST MEETING CELL (NMC)
INPUT : same as above + third line has 2 numbers whose nearest meeting cell is to be found.
SAMPLE INPUT
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
9 2 (need to find out meeting point of 9 , 2 in the mesh/graph)
OUTPUT
4
CODE:
def main():
testCASES=int(input())
# testCASES=1
for case_number in range(testCASES):
meshsize=input()
mesh=input()
# mesh='4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21'
det=input()
# det='9 2'
mesh=[int(x) for x in mesh.split()]
det=[int(x) for x in det.split()]
n1=det[0]
n2=det[1]
n1path=[]
n2path=[]
for i in range(len(mesh)):
if not n1path:
n1path.append(mesh[n1])
else:
n1path.append(mesh[n1path[i-1]])
if not n2path:
n2path.append(mesh[n2])
else:
n2path.append(mesh[n2path[i-1]])
nearestList=[]
try:
for x in n1path:
nearestList.append(n2path.index(x))
NEAREST_NODE=n2path[min(nearestList)]
except Exception as e:
NEAREST_NODE = -1
# print(n1path,n2path)
print(NEAREST_NODE)
main()
WORKING:
walks paths from given 2 points, and calculate first common point of n1path and n2path, by using min() function on indices of nearest list. naming is arbitary, but thats the core algo.
it can handle if cycles are present, and still return the first intersection point.
returns -1 if no matches are found.
This is one more variant of the problem, apart from the normal inpt, we're given two nodes, src and dest, and we have to output the node which is the closest to both src and dest.
Here's my solution to finding nearest cell from both src and dest
#include<bits/stdc++.h>
using namespace std;
//returns answer
int solution(vector<int> arr, int src, int dest){
// Two maps, visA for distance from src and visB for distance from dest
// They serve two purpose, if visA[x] == 0, that means we haven't reached that node yet,
// and if it holds any value, say d, that means it is d distance away from the particular node
map<int,int> visA,visB;
int start = arr[src];
int curr = 1;
set<int> s; // contains unique set of nodes to check at last
// iniitializing final nodes
for(auto &x: arr){
s.insert(x);
}
// traversing until we get to a cell where we've already reached
while(visA[start] == 0){
visA[start] = curr; // Marcking the distance
curr++;
start = arr[start];
if(start == -1){
break; // Getting out if we get to a node who is not pointing at any other node
}
}
start = arr[dest];
// Same logic as above but traversing from dest
while(visB[start] == 0){
visB[start] = curr;
curr++;
start = arr[start];
if(start == -1){
break;
}
}
// This is an array of two values, vp[i].first holds the sum of distance of vp[i].second from src and dest.
vector<pair<int,int>> vp;
for(auto &x: s){
if(visA[x] != 0 && visB[x] != 0){ // Checking if we ever got to that particular node from both src and dest or not
pair<int,int> p = {visA[x] + visB[x], x};
vp.push_back(p);
}
}
// sorting and finding the node with list sum of visA[} + visB[]
sort(vp.begin(), vp.end());
return vp[0].second;
}
int main(){
int n; cin>>n;
vector<int> v;
for(int i = 0; i<n; i++){
int a; cin>>a;
v.push_back(a);
}
int a,b; cin>>a>>b;
cout << (solution(v,a,b));
}
function largestCycle(edges) {
var result, visitedFrom, startCell, cell, cells;
result = [];
visitedFrom = Array(edges.length).fill(-1);
for (startCell = 0; startCell < edges.length; startCell++) {
cells = [];
for (cell=startCell; cell>-1 && visitedFrom[cell]===-1; cell = edges[cell]) {
visitedFrom[cell] = startCell;
cells.push(cell);
}
if (cell > -1 && visitedFrom[cell] === startCell) {
cells = cells.slice(cells.indexOf(cell));
if (cells.length > result.length) result = cells;
}
}
return result;
}
// Snippet I/O
var input = document.querySelector('textarea');
var output = document.querySelector('span');
(input.oninput = function () {
// Get input as array of numbers
var edges = input.value.trim().split(/\s+/).map(Number);
// Apply algorithm
var cycle = largestCycle(edges);
// Output result
output.textContent = cycle.length + ': ' + JSON.stringify(cycle);
})(); // Execute also at page load
Input:<br>
<textarea style="width:100%">4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21</textarea><br>
Greatest Cycle: <span></span>

Finding Longest Path in Directed Acyclic Graph

I need to find the longest path from node 0 for a set of Directed Acyclic Graphs. I am using the Longest Path Problem algorithm from Wikipedia. I have got the algorithm working for most graphs, but for others it doesn't give a correct result. The algorithm is:
private static int DAGLongestPath(Graph G) {
int n = G.order();
int[] topOrder = new int[n];
topOrder = topSort2(G);
for (int i = 0; i < topOrder.length; i++) {
topOrder[i] -= 1;
}
int[] lengthTo = new int[n];
for (int i = 0; i < n; i++) lengthTo[i] = 0;
for (int i = 0; i < topOrder.length; i++) { //for each vertex v in topOrder(G) do
ArrayList<Integer> neighbors = new ArrayList<Integer>();
neighbors = G.neighbors(topOrder[i]);
int v = topOrder[i];
for (int j = 0; j < neighbors.size(); j++) {
int w = neighbors.get(j);
if(lengthTo[w] <= lengthTo[v] + 1) {
lengthTo[w] = lengthTo[v] + 1;
}
}
}
int max = 0;
for (int i = 0; i < n; i++ ) {
max = Math.max(max, lengthTo[i]);
}
return max;
}
The graph implementation uses an Adjacency List to store the graphs. If I pass a graph like:
9 // Number of nodes
0: 1 2
1: 2 3 4
2: 4 8
3: 5 6
4: 6 7 8
5:
6:
7:
8: 7
I get the answer 5, which is correct. However, if I pass the graph:
8 // Number of nodes
0: 2 3
1:
2:
3: 5
4: 5
5: 2
6: 7
7: 4
Then I get 2, when the correct answer should be 3.
The TopSort2 algorithm I am using is:
public static int[] topSort2(Graph G){
int n = G.order();
int[] sort = new int[n];
int[] inDeg = new int[n];
for (int i=0; i<n; i++) inDeg[i] = G.inDegree(i);
int cnt = 0;
boolean progress = true;
//
while (progress){
progress = false;
for (int v=0; v<n; v++){
if (inDeg[v] == 0){
sort[v] = ++cnt;
progress = true;
inDeg[v] = -1;
ArrayList<Integer> nbrs = G.neighbors(v);
for (int u : nbrs){
inDeg[u] = inDeg[u] - 1;
}
}
} // for v
} // while nodes exist with inDegree == 0.
return sort;
}
DFS algorithms are:
private static int doDFS(Graph G, int v, int[] PreOrder, int[] PostOrder, countPair cnt){
PreOrder[v] = cnt.inc1();
int dfsTotal = 0;
ArrayList<Integer> nbrs = G.neighbors(v);
for (int i : nbrs) {
if (PreOrder[i] == 0) {
int dfsTemp = doDFS(G, i, PreOrder, PostOrder, cnt);
dfsTotal = Math.max(dfsTotal, dfsTemp);
}
}
PostOrder[v] = cnt.inc2();
if(nbrs.size() > 0 ) {
dfsTotal++;
}
return dfsTotal;
}
public static int DFS(Graph G, int v, int[] PreOrder, int[] PostOrder){
int n = G.order();
int total = 0;
for (int i=0; i<n; i++) PreOrder[i] = PostOrder[i] = 0;
countPair cnt = new countPair();
total = doDFS(G, v, PreOrder, PostOrder, cnt);
return total;
}
private static class countPair { // private counters for DFS search
int cnt1, cnt2;
int inc1() { return ++cnt1; }
int inc2() { return ++cnt2; }
}
I think the problem is your topSort2() function
In the int[] sort returned by the function, the index denotes the vertex and the content denotes the order. i.e. if you have sort[1] = 2, you mean vertex 1 is the second vertex
However when you use it, you take the content as the vertex. i.e. you take topOrder[i] as a vertex, while actually i should be the vertex

Help with algorithm problem from SPOJ

I thought it would be a fun problem: Prime Path
But...It is hard for me.
My only idea is "To do something with knapsack problem".. and no other ideas.
Could You track me for good way?
It's not for any challenge or University homework. I just want to learn something.
_
Ok, but firstly, how to find this prime numbers? Do i need to find all 4digit prime numbers, add it to graph?
For now i have generating all prime numbers.
http://pastebin.com/wbhRNRHQ
Could You give me sample code to declare graph build on neighbour list?
Seems like a straightforward graph path finding problem.
Take all 4 digit primes as the vertices. Connect two with an edge, if we can go from one to the other.
Now given two, you need to find the shortest path between them, in the graph we just formed. A simple BFS (breadth-first-search) should do for that.
For programming contests with time limits, you could even hardcode every possible prime pair path and get close to zero running time!
Build a graph where the nodes are all the 4 digit prime numbers, and there are arcs everywhere two numbers have three digits in common. From there, it's a basic graph traversal to find the lowest-cost path from one node to another.
I came across a similar question where I had to convert one 4 digit prime number 1033 to another 4 digit prime number 3739 in minimum number of steps. I was able to solve the problem, it might not be efficient but here is the working code for the same.
Below code has been written in Java
import java.util.*;
public class PrimeNumberProblem {
public static void main(String... args) {
System.out.println("Minimum number of steps required for converting 1033 to 3739 are = "
+ getMinSteps(1033, 3739));
}
public static int getMinSteps(int a, int b) {
if (a == b)
return 0;
List<Integer> primes = new ArrayList<>();
// get all the 4 digit prime numbers
primes = getPrimeNumbers();
// consists of graph with vertices as all the prime numbers
Graph graph = addNumbersToGraph(primes);
// adding edges to the graph vertices
Graph finalGraph = addWeightToGraph(graph);
// min number of steps required
int result = findShortestRoute(finalGraph.getVertex(a), finalGraph.getVertex(b));
return result;
}
private static int findShortestRoute(Vertex source, Vertex dest) {
if (source.getVertexValue() == dest.getVertexValue())
return 0;
// step 1 Initialize the queue. Also Map to store path
Queue<Vertex> visitedQueue = new LinkedList<>();
Map<Vertex, Vertex> currentPrevMap = new HashMap<Vertex, Vertex>();
// step 2 start from visiting S (starting node), and mark it visited, add to queue
Map<Integer, Boolean> visited = new HashMap<Integer, Boolean>();
visited.put(source.getVertexValue(), true);
visitedQueue.add(source);
int level = 0;
// step 3 Repeat until queue is empty
while (!visitedQueue.isEmpty()) {
// step 4 remove from queue
Vertex current = visitedQueue.remove();
if (current.getVertexValue() == dest.getVertexValue()) {
printPath(source, dest, currentPrevMap);
return level;
} else if (current.getAdjacentVertices().size() > 0) {
level++;
}
// step 5 add each of the unvisited neighbour and mark visited
for (Vertex adjacentVertex : current.getAdjacentVertices()) {
Integer value = adjacentVertex.getVertexValue();
if (value == dest.getVertexValue()) {
currentPrevMap.put(adjacentVertex, current);
printPath(source, dest, currentPrevMap);
return level;
}
if (visited.get(value) == null) {
currentPrevMap.put(adjacentVertex, current);
// mark visited and enqueue it
visited.put(value, true);
visitedQueue.add(adjacentVertex);
}
}
}
// not found
System.out.println("Dest vertex not found");
return -1;
}
private static void printPath(Vertex source, Vertex dest, Map<Vertex, Vertex> currentPrevMap) {
Vertex node = dest;
System.out.println("Reverse Path from source: " + source.getVertexValue() + " to dest: "
+ dest.getVertexValue());
while (node != source) {
System.out.println(node.getVertexValue());
node = currentPrevMap.get(node);
}
System.out.println(source.getVertexValue());
}
private static Graph addWeightToGraph(Graph graph) {
List<Vertex> vertices = graph.getAllVertices();
for (Vertex i : vertices) {
for (Vertex j : vertices) {
if (i.equals(j))
continue;
if (distance(i, j) == 1) {
i.getAdjacentVertices().add(j);
// i.addEdge(new Edge(i, j, 1));
}
}
}
return graph;
}
private static int distance(Vertex source, Vertex dest) {
if (source.getVertexValue() == dest.getVertexValue()) {
return 0;
}
char[] numA = extractIntegers(source.getVertexValue());
char[] numB = extractIntegers(dest.getVertexValue());
int len1 = numA.length;
int tracker = 0;
for (int i = 0; i < len1; i++) {
if (numA[i] != numB[i]) {
numA[i] = numB[i];
tracker++;
String sA = String.copyValueOf(numA);
String sB = String.copyValueOf(numB);
// if we have reached destination
if (Integer.parseInt(sA) == Integer.parseInt(sB)) {
return tracker;
}
}
}
return tracker;
}
private static char[] extractIntegers(int i) {
char[] arr = Integer.toString(i).toCharArray();
return arr;
}
private static Graph addNumbersToGraph(List<Integer> primes) {
Graph g = new Graph();
for (Integer prime : primes) {
g.addVertex(new Vertex(prime));
}
return g;
}
private static List<Integer> getPrimeNumbers() {
List<Integer> fourDigitPrimes = new ArrayList<>();
fourDigitPrimes.add(1033);
fourDigitPrimes.add(1733);
fourDigitPrimes.add(3733);
fourDigitPrimes.add(3739);
// for (int i = 1000; i < 9999; i++) {
// if (isPrime(i))
// fourDigitPrimes.add(i);
// }
return fourDigitPrimes;
}
private static boolean isPrime(int i) {
for (int k = 2; k < Math.sqrt(i); k++) {
if (i % k == 0)
return false;
}
return true;
}
}
class Graph {
public List<Vertex> vertexList = new ArrayList<Vertex>();
public void addVertex(Vertex V) {
vertexList.add(V);
}
public List getAllAdjacentNodes(Vertex V) {
return V.getAdjacentVertices();
}
public List getAllVertices() {
return vertexList;
}
public Vertex getVertex(int val) {
Iterator<Vertex> keys = vertexList.iterator();
while (keys.hasNext()) {
Vertex v = keys.next();
if (v.getVertexValue() == val)
return v;
}
return null;
}
}
class Vertex {
int value;
private List<Vertex> adjacentVertices = new ArrayList<Vertex>();
public Vertex(int v) {
this.value = v;
}
public List<Vertex> getAdjacentVertices() {
return adjacentVertices;
}
public int getVertexValue() {
return value;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Vertex vertex = (Vertex) o;
return value == vertex.value;
}
#Override
public int hashCode() {
return value;
}
}
Look into "breadth-first search". Also worth bearing in mind here that the problem can be approached "from both ends" simultaneously (a chain from numbers X to Y can be reversed to get Y to X, and you can exploit this). Precalculating primes will avoid much computation along the way.
I'd run a BFS using probable prime testing, which would work relatively well with only 4 digit numbers. With only 4 digits, also, you may want to use more exacting methods to produce all primes to compare against for faster prime checking.
Could You give me sample code to
declare graph build on neighbour list?
here is a sample code for breadth first search
public static final int MAX = 10000;
boolean[] prime = new boolean[MAX];
int[] dist = new int[MAX];
//get digit i [1 to 4] in num
public int getDigit(int num,int i){
return num % ((int)Math.pow(10, i)) / ((int) Math.pow(10, i-1));
}
//set digit i to d
public int setDigit(int num,int i,int d){
return (num - getDigit(num, i)*(int)Math.pow(10, i-1)) + d * (int)Math.pow(10,i-1);
}
public int bfs(int start,int end){
Queue<Integer> q = new LinkedList<Integer>();
q.add(start);
HashSet<Integer> visited = new HashSet<Integer>();
visited.add(start);
dist[start] = 0;
int x,y,d = 0;
while (q.size() > 0){
x = q.poll();
d = dist[x];
if (x == end) return d;
for (int i = 1; i < 5; i++) {
//digit number i
for (int j = 0; j < 10; j++) {
//avoid setting last digit
if (j == 0 && i == 4) continue;
//set digit number i to j
y = setDigit(x, i, j);
if (prime[y] && y != x && !visited.contains(y)){
q.add(y);
visited.add(y);
dist[y] = d + 1;
}
}
}
}
return -1;
}
Here is my solution using BFS and I have already saved all 4 digit prime numbers into an array as there is no need to write a function to calculate the prime numbers. I hope it helps
#include<stdio.h>
int hash[10000];
int a,b,ans,level,new_num,count;
int prime[] = {1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499,1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907,1913,1931,1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377,2381,2383,2389,2393,2399,2411,2417,2423,2437,2441,2447,2459,2467,2473,2477,2503,2521,2531,2539,2543,2549,2551,2557,2579,2591,2593,2609,2617,2621,2633,2647,2657,2659,2663,2671,2677,2683,2687,2689,2693,2699,2707,2711,2713,2719,2729,2731,2741,2749,2753,2767,2777,2789,2791,2797,2801,2803,2819,2833,2837,2843,2851,2857,2861,2879,2887,2897,2903,2909,2917,2927,2939,2953,2957,2963,2969,2971,2999,3001,3011,3019,3023,3037,3041,3049,3061,3067,3079,3083,3089,3109,3119,3121,3137,3163,3167,3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253,3257,3259,3271,3299,3301,3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371,3373,3389,3391,3407,3413,3433,3449,3457,3461,3463,3467,3469,3491,3499,3511,3517,3527,3529,3533,3539,3541,3547,3557,3559,3571,3581,3583,3593,3607,3613,3617,3623,3631,3637,3643,3659,3671,3673,3677,3691,3697,3701,3709,3719,3727,3733,3739,3761,3767,3769,3779,3793,3797,3803,3821,3823,3833,3847,3851,3853,3863,3877,3881,3889,3907,3911,3917,3919,3923,3929,3931,3943,3947,3967,3989,4001,4003,4007,4013,4019,4021,4027,4049,4051,4057,4073,4079,4091,4093,4099,4111,4127,4129,4133,4139,4153,4157,4159,4177,4201,4211,4217,4219,4229,4231,4241,4243,4253,4259,4261,4271,4273,4283,4289,4297,4327,4337,4339,4349,4357,4363,4373,4391,4397,4409,4421,4423,4441,4447,4451,4457,4463,4481,4483,4493,4507,4513,4517,4519,4523,4547,4549,4561,4567,4583,4591,4597,4603,4621,4637,4639,4643,4649,4651,4657,4663,4673,4679,4691,4703,4721,4723,4729,4733,4751,4759,4783,4787,4789,4793,4799,4801,4813,4817,4831,4861,4871,4877,4889,4903,4909,4919,4931,4933,4937,4943,4951,4957,4967,4969,4973,4987,4993,4999,5003,5009,5011,5021,5023,5039,5051,5059,5077,5081,5087,5099,5101,5107,5113,5119,5147,5153,5167,5171,5179,5189,5197,5209,5227,5231,5233,5237,5261,5273,5279,5281,5297,5303,5309,5323,5333,5347,5351,5381,5387,5393,5399,5407,5413,5417,5419,5431,5437,5441,5443,5449,5471,5477,5479,5483,5501,5503,5507,5519,5521,5527,5531,5557,5563,5569,5573,5581,5591,5623,5639,5641,5647,5651,5653,5657,5659,5669,5683,5689,5693,5701,5711,5717,5737,5741,5743,5749,5779,5783,5791,5801,5807,5813,5821,5827,5839,5843,5849,5851,5857,5861,5867,5869,5879,5881,5897,5903,5923,5927,5939,5953,5981,5987,6007,6011,6029,6037,6043,6047,6053,6067,6073,6079,6089,6091,6101,6113,6121,6131,6133,6143,6151,6163,6173,6197,6199,6203,6211,6217,6221,6229,6247,6257,6263,6269,6271,6277,6287,6299,6301,6311,6317,6323,6329,6337,6343,6353,6359,6361,6367,6373,6379,6389,6397,6421,6427,6449,6451,6469,6473,6481,6491,6521,6529,6547,6551,6553,6563,6569,6571,6577,6581,6599,6607,6619,6637,6653,6659,6661,6673,6679,6689,6691,6701,6703,6709,6719,6733,6737,6761,6763,6779,6781,6791,6793,6803,6823,6827,6829,6833,6841,6857,6863,6869,6871,6883,6899,6907,6911,6917,6947,6949,6959,6961,6967,6971,6977,6983,6991,6997,7001,7013,7019,7027,7039,7043,7057,7069,7079,7103,7109,7121,7127,7129,7151,7159,7177,7187,7193,7207,7211,7213,7219,7229,7237,7243,7247,7253,7283,7297,7307,7309,7321,7331,7333,7349,7351,7369,7393,7411,7417,7433,7451,7457,7459,7477,7481,7487,7489,7499,7507,7517,7523,7529,7537,7541,7547,7549,7559,7561,7573,7577,7583,7589,7591,7603,7607,7621,7639,7643,7649,7669,7673,7681,7687,7691,7699,7703,7717,7723,7727,7741,7753,7757,7759,7789,7793,7817,7823,7829,7841,7853,7867,7873,7877,7879,7883,7901,7907,7919,7927,7933,7937,7949,7951,7963,7993,8009,8011,8017,8039,8053,8059,8069,8081,8087,8089,8093,8101,8111,8117,8123,8147,8161,8167,8171,8179,8191,8209,8219,8221,8231,8233,8237,8243,8263,8269,8273,8287,8291,8293,8297,8311,8317,8329,8353,8363,8369,8377,8387,8389,8419,8423,8429,8431,8443,8447,8461,8467,8501,8513,8521,8527,8537,8539,8543,8563,8573,8581,8597,8599,8609,8623,8627,8629,8641,8647,8663,8669,8677,8681,8689,8693,8699,8707,8713,8719,8731,8737,8741,8747,8753,8761,8779,8783,8803,8807,8819,8821,8831,8837,8839,8849,8861,8863,8867,8887,8893,8923,8929,8933,8941,8951,8963,8969,8971,8999,9001,9007,9011,9013,9029,9041,9043,9049,9059,9067,9091,9103,9109,9127,9133,9137,9151,9157,9161,9173,9181,9187,9199,9203,9209,9221,9227,9239,9241,9257,9277,9281,9283,9293,9311,9319,9323,9337,9341,9343,9349,9371,9377,9391,9397,9403,9413,9419,9421,9431,9433,9437,9439,9461,9463,9467,9473,9479,9491,9497,9511,9521,9533,9539,9547,9551,9587,9601,9613,9619,9623,9629,9631,9643,9649,9661,9677,9679,9689,9697,9719,9721,9733,9739,9743,9749,9767,9769,9781,9787,9791,9803,9811,9817,9829,9833,9839,9851,9857,9859,9871,9883,9887,9901,9907,9923,9929,9931,9941,9949,9967,9973};
int size = sizeof(prime)/sizeof(prime[0]);
int bfs(int,int);
typedef struct q{
int x, c;
} queue;
queue qq[10000];
int isprime(int x)
{
int l,r,m;
l=m=0; r=size-1;
while (l <= r)
{
int m = l + (r-l)/2;
if (prime[m] == x)
return 1;
if (prime[m] < x)
l = m + 1;
else
r = m - 1;
}
return 0;
}
int bfs(int num1,int num2)
{
int i,j,k,p,q,n;
new_num=p=q=0;
i=0;
j=1;
qq[i].x = num1;
qq[i].c = 0;
hash[num1] = 1;
while(i!=j)
{ n = qq[i].x;
level = qq[i].c;
if(n==num2)
{
count = level;
return count;
}
level++;
p = n%1000;
for(k=1;k<10;k++)
{ new_num = (k*1000)+ p;
if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num]))
{
hash[new_num] = 1;
qq[j].x = new_num;
qq[j].c = level;
j++;
}}
p=q=new_num=0;
p = n/1000;
q = n%100;
for(k=0;k<10;k++)
{ new_num = (p*1000)+k*100+q;
if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num]))
{
hash[new_num] = 1;
qq[j].x = new_num;
qq[j].c = level;
j++;
}}
p=q=new_num=0;
p = n/100;
q = n%10;
for(k=0;k<10;k++)
{ new_num = (p*100)+k*10+q;
if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num]))
{
hash[new_num] = 1;
qq[j].x = new_num;
qq[j].c = level;
j++;
}}
p=q=new_num=0;
p = n/10;
for(k=0;k<10;k++)
{ new_num = (p*10)+k;
if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num]))
{
hash[new_num] = 1;
qq[j].x = new_num;
qq[j].c = level;
j++;
}}
p=q=new_num=0;
i++;
}
return -1;}
int main()
{
int v,tc;
setbuf(stdout,NULL);
scanf("%d",&tc);
for(v=1;v<=tc;v++)
{ int i,j;
a=b=ans=level=new_num=count=0;
for(i=0;i<10000;i++)
{qq[i].x=0;
qq[i].c=0;
hash[i]=0;}
scanf("%d%d",&a,&b);
if(a==b)
{ ans = 0;}
else
{ ans = bfs(a,b);}
printf("Case #%d\n", v);
if(ans==-1)
{
printf("Impossible\n");
}
else
{printf("%d\n",ans);}
}
return 0;
}
My Python solution using BFS:
import queue
# Class to represent a graph
class Graph:
def __init__(self, V):
self.V = V # No. of vertices
self.prime_list = [[] for i in range(V)]
# function to add an edge to graph
def addedge(self, V1, V2):
self.prime_list[V1].append(V2)
self.prime_list[V2].append(V1)
def bfs(self, in1, in2):
visited = [0] * self.V
que = queue.Queue()
visited[in1] = 1
que.put(in1)
while not que.empty():
prime_index = que.get()
i = 0
while i < len(self.prime_list[prime_index]):
if not visited[self.prime_list[prime_index][i]]:
visited[self.prime_list[prime_index][i]] = visited[prime_index] + 1
que.put(self.prime_list[prime_index][i])
if self.prime_list[prime_index][i] == in2:
return visited[self.prime_list[prime_index][i]] - 1
i += 1
# // Finding all 4 digit prime numbers
def SieveOfEratosthenes(v):
# Create a boolean array "prime[0..n]" and initialize all entries it as true. A value in prime[i] will be
# finally be false if i is Not a prime, else true.
n = 9999
prime = [True] * (n + 1)
p = 2
while p * p <= 9999:
if prime[p]:
i = p * p
while i <= 9999:
prime[i] = False
i = i + p
p = p + 1
# v = []
for i in range(1000, n + 1):
if prime[i]:
v.append(i)
return v
def compare(a, b):
diff = 0
while a:
if a % 10 != b % 10:
diff += 1
a //= 10
b //= 10
# If the numbers differ only by a single # digit return true else false
if diff > 1:
return False
return True
def shortestPath(num1, num2):
# Generate all 4 digit
pset = []
SieveOfEratosthenes(pset)
# Create a graph where node numbers # are indexes in pset[] and there is
# an edge between two nodes only if # they differ by single digit.
g = Graph(len(pset))
for i in range(len(pset)):
for j in range(i + 1, len(pset)):
if compare(pset[i], pset[j]):
g.addedge(i, j)
# Since graph nodes represent indexes # of numbers in pset[], we find indexes of num1 and num2.
in1, in2 = None, None
for j in range(len(pset)):
if pset[j] == num1:
in1 = j
for j in range(len(pset)):
if pset[j] == num2:
in2 = j
return g.bfs(in1, in2)
# Driver code
if __name__ == '__main__':
num1 = 1033
num2 = 8179
print(shortestPath(num1, num2))

Resources