Swap positions of two nodes in a GraphViz diagram (DOT) - graphviz

I use the DOT language to create a diagram in R. As I get a strange result, I am interested how to swap positions of two nodes: node 8 and node c4?
The code:
digraph DAG {
# Initialization of node attributes
node [shape = box, color = blue]; 2; 3; 4;
# Revision to node attributes
{ node [shape = box,style = filled,fillcolor = yellow]; 8}
# Revision to node attributes
{ node [shape = diamond, color = "red"]; c1; c2; c3; c4}
{ rank=same; c1; c2; c3}
{ rank=same; 8; c4}
# Initialization of edge attributes
edge [color = green, rel = yields]
# Edge statements
2->c1 [headport = w];
c1->c2->c3
c2->c1 [tailport = n, headport = n];
8->c3 [tailport = n, headport = s];
c3->3 [tailport = e, headport = n];
c3->c2 [tailport = n, headport = n];
3->c4 [tailport = s, headport = n];
c4->4 [tailport = s, headport = n];
c4->8 [tailport = w, headport = e];
}
The (incorrect) result is:

for "wrong way" edges you may
swap nodes and use attribute dir = back to invert its 'force'
use attribute constraint = none to disable its 'force'
in your case you substitute
8->c4 [tailport = e, headport = w, dir = back];
by either
c4->8 [tailport = w, headport = e, constraint = none];
or by
8->c4 [tailport = e, headport = w, dir = back];

Related

shortest path going through m edges

Hello there smart people.
I have a following graph problem.
Given a complete, directed, wieghted graph with n vertices, find the length of the shortest path (starting at any vertex) going through m - 1 edges (edges in the path might repeat).
As for the limits n <= 200, m <= 1e9.
Looking at the limits I can say there must be some clever way without some sort of dp and graph traversing but I just cant think of anything like that.
Thanks in advance.
Example:
n = 3, m = 5
edges:
1 -> 2 weight = 10,
1 -> 3 weight = 100,
2 -> 1 weight = 10,
2 -> 3 weight = 50,
3 -> 1 weight = 30,
3 -> 2 weight = 70,
answer would be 40 (1 -> 2 -> 1 -> 2 -> 1)
A naive solution would be to run BFS (breadth-first search) until the mth level and maintain the minimum sum of weights and return it.
But in the question it says we can include the vertex as many times till there is a path between them, so now we can do the below steps:
Calculate all the cycles present in the graph, we can reuse these cycles in calculating the minimum weight possible.
for example:
in the question, there is a cycle present 1-->2-->1 of length=3 weight=20, the value of m = 5, now we can use this path twice, but if m was 6 then we are left with 1 more node to include.
Now we can calculate the min path (to include leftover nodes) of length l (which is 1 if m=6) from 1 and add it to the above weight. (which will we 1-->2 =10)
Repeat the steps 1 and 2 for every cycle present in the graph and maintain the minimum sum.
Below is the c++ code describing the above solution (it may not be 100% correct, but you will get the basic idea)
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
struct Edge{
int src, dest, weight;
};
struct Node{
int start_vertex, end_vertex, weight, edge_count=0;
};
class Graph{
public:
vector<vector<pair<int, int>>> adjList;
int V;
Graph(vector<Edge> edges, int V){
adjList.resize(V+1);
this->V = V;
for(Edge edge:edges){
adjList[edge.src].push_back({edge.dest, edge.weight});
}
}
};
int BFS(Graph &g, int m){
queue<Node> Q;
vector<Node> cycles;
// to store min path from vertex i of length j
vector<vector<int>> dp(g.V+1, vector<int>(g.V+1, INT_MAX));
for(int i=0; i<=g.V; i++)
dp[i][0] = 0;
for(int i=1; i<=g.V; i++){
Q.push({i, i, 0, 1});
}
while(!Q.empty()){
Node top = Q.front();
Q.pop();
if(top.edge_count >= g.V) break;
int v = top.end_vertex;
int start_vertex = top.start_vertex;
int weight = top.weight;
int edge_count = top.edge_count;
for(auto x:g.adjList[v]){
// finding all the cycles
if(x.first == start_vertex){
Node n = {start_vertex, v, weight+x.second, edge_count+1};
cycles.push_back(n);
}else{
Q.push({start_vertex, x.first, weight+x.second, edge_count+1});
}
if(dp[start_vertex][edge_count] > weight+x.second){
dp[start_vertex][edge_count] = weight+x.second;
}
}
}
// finding minimum:
int min_weight = INT_MAX;
if(m<=g.V){
for(int i=1; i<=g.V; i++){
min_weight = min(min_weight, dp[i][m]);
}
}
// checking all the cycles for reusability and maintaining min sum
for(int i=0; i<cycles.size(); i++){
int sum = cycles[i].weight;
int length_left_to_cover = m-cycles[i].edge_count;
sum += length_left_to_cover/(cycles[i].edge_count-1) * cycles[i].weight;
int vertices_left_to_include = 0;
if(m-cycles[i].edge_count>0){
vertices_left_to_include = (m-cycles[i].edge_count)%(cycles[i].edge_count-1);
}
min_weight = min(min_weight, sum+dp[cycles[i].start_vertex][vertices_left_to_include]);
}
return min_weight;
}
// 1 -> 2 weight = 10,
// 1 -> 3 weight = 100,
// 2 -> 1 weight = 10,
// 2 -> 3 weight = 50,
// 3 -> 1 weight = 30,
// 3 -> 2 weight = 70,
int main(){
vector<Edge> edges = {
{1, 2, 10},
{1, 3, 100},
{2, 1, 10},
{2, 3, 50},
{3, 1, 30},
{3, 2, 70}
};
int V = 3;
int m = 5;
Graph g(edges, V);
cout<<"Min weight: "<<BFS(g, m);
}
Output:
Min weight: 40

Finding Final Arrangement

I came across this question in recent interview :
Given an array of pairs representing a number inserted at which position, we need to find final arrangement. If there is already a number at that position, we need to shift array from that position to the right and put that number at desired position.
e.g. A = {0, 1, 2, 3, 4}, B = {0, 1, 2, 1, 2} (Ai represents a number and Bi represents its desired position ) , so, array C can be filled as follows :
C = {0, _, _, _, _} => {0,1, _ ,_ ,_ } => {0,1,2,_ ,_ } =>{0,3,1,2,_ } =>{0,3,4,1,2}
Constaints : 0 <= Ai, Bi < N (N is length of an array)
We need to find final array C. I need better approach than applying brute force for this solution. Thanks in advance.
First, let's consider the T operator which for a position i, returns T(i) = i+1 (that is the element is switched to the right)
Obviously, T(T(i)) = i+2, and we can note T^n(i) = i+n
Now consider a linked list whose node is
{
idx: i,//idx of the value upon insertion (as found in B)
value:value,
tn:Number //T^n
}
pseudo code be like
insertElem(L, i, val):
node = L
while node
acc += node.tn //sum all the shifts
curIdx = node.idx + acc
if curIdx == i:
insertElemBefore(node, i, val)
node.tn++
return
if curIdx > i:
insertElemBefore(node, i, val)
node = node.next
//we could not find any elem to shift
//just insert elem at the end
function insertElem(L, i, val){
let el = {idx:i, val:val, tn:0}
let acc = 0;
let front = L;
while(L.next){
let next = L.next;
acc += next.tn;
if(acc + next.idx >= i){
L.next = el;
if(acc + next.idx == i){
el.next = next;
next.tn++;
}
return front;
}
L = L.next;
}
L.next = el;
el.next = null;
return front;
}
function main(A,B){
let L = {next:null}
B.forEach((idx,i)=>{
L = insertElem(L, idx, A[i]);
});
let v = [];
while(L = L.next){
v.push(L.val);
}
return v;
}
console.log(main([0,1,2,3,4],[0,1,2,1,2]))

How to detect cycles in a directed graph using the iterative version of DFS?

In the recursive DFS, we can detect a cycle by coloring the nodes as WHITE, GRAY and BLACK as explained here.
A cycle exists if a GRAY node is encountered during the DFS search.
My question is: When do I mark the nodes as GRAY and BLACK in this iterative version of DFS? (from Wikipedia)
1 procedure DFS-iterative(G,v):
2 let S be a stack
3 S.push(v)
4 while S is not empty
5 v = S.pop()
6 if v is not labeled as discovered:
7 label v as discovered
8 for all edges from v to w in G.adjacentEdges(v) do
9 S.push(w)
You could do that simply by not popping the stack element right away.
For every iteration, do v = stack.peek() and if v is White, mark it as Grey and go ahead exploring its neighbours.
However, if v is Grey, it means that you have encountered v for the second time in the stack and you have completed exploring it. Mark it Black and continue the loop.
Here's how your modified code should look like:
procedure DFS-iterative(G,v):
let S be a stack
S.push(v)
while S is not empty
v = S.peek()
if v is not labeled as Grey:
label v as Grey
for all edges from v to w in G.adjacentEdges(v) do
if w is labeled White do
S.push(w)
elif w is labeled Grey do
return False # Cycle detected
# if w is black, it's already explored so ignore
elif v is labeled as Grey:
S.pop() # Remove the stack element as it has been explored
label v as Black
If you're using a visited list to mark all visited nodes and another recStack i.e a list which keeps track of nodes currently being explored, then what you can do is, instead of popping the element from stack, just do stack.peek(). If the element is not visited (it means you're encountering that element for the first time in the stack), just mark it True in visited and recStack and explore its children.
However, if the peek() value is already visited, it means you're ending the exploration of that node so just pop it and make it's recStack as False again.
One option is to push each node twice to the stack along the information if you're entering or exiting it. When you pop a node from stack you check if you're entering or exiting. In case of enter color it gray, push it to stack again and advance to neighbors. In case of exit just color it black.
Here's a short Python demo which detects a cycle in a simple graph:
from collections import defaultdict
WHITE = 0
GRAY = 1
BLACK = 2
EDGES = [(0, 1), (1, 2), (0, 2), (2, 3), (3, 0)]
ENTER = 0
EXIT = 1
def create_graph(edges):
graph = defaultdict(list)
for x, y in edges:
graph[x].append(y)
return graph
def dfs_iter(graph, start):
state = {v: WHITE for v in graph}
stack = [(ENTER, start)]
while stack:
act, v = stack.pop()
if act == EXIT:
print('Exit', v)
state[v] = BLACK
else:
print('Enter', v)
state[v] = GRAY
stack.append((EXIT, v))
for n in graph[v]:
if state[n] == GRAY:
print('Found cycle at', n)
elif state[n] == WHITE:
stack.append((ENTER, n))
graph = create_graph(EDGES)
dfs_iter(graph, 0)
Output:
Enter 0
Enter 2
Enter 3
Found cycle at 0
Exit 3
Exit 2
Enter 1
Exit 1
Exit 0
In DFS, end of a branch is nodes that has no children these nodes is Black. Then checked parents of these nodes. If a parent do not has Gray child then it is Black. Likewise, if you continue to set black color to nodes, color of all nodes becomes black.
For example, I want to perform DFS in graph below.
DFS starts from u and visited u -> v -> y -> x. x has no children and you should change color of this node to Black.
Then return to parent of x in visited path according to discovery time. So parent of x is y. y has no children with Gray color so you should change color of this node to Black.
I have solved this problem as a solution for this Leetcode problem - https://leetcode.com/problems/course-schedule/
I have implemented it in Java - using recursive DFS using colors, recursive DFS using visited array, iterative DFS and BFS using indegree and calculating topological sort.
class Solution {
//prereq is the edges and numCourses is number of vertices
public boolean canFinish(int numCourses, int[][] prereq) {
//0 -> White, -1 -> Gray, 1 -> Black
int [] colors = new int[numCourses];
boolean [] v = new boolean[numCourses];
int [] inDegree = new int[numCourses];
Map<Integer, List<Integer>> alMap = new HashMap<>();
for(int i = 0; i < prereq.length; i++){
int s = prereq[i][0];
int d = prereq[i][1];
alMap.putIfAbsent(s, new ArrayList<>());
alMap.get(s).add(d);
inDegree[d]++;
}
// if(hasCycleBFS(alMap, numCourses, inDegree)){
// return false;
// }
for(int i = 0; i < numCourses; i++){
if(hasCycleDFS1(i, alMap, colors)){
// if(hasCycleDFS2(i, alMap, v)){
//if(hasCycleDFSIterative(i, alMap, colors)){
return false;
}
}
return true;
}
//12.48
boolean hasCycleBFS(Map<Integer, List<Integer>> alMap, int numCourses, int [] inDegree){
//short [] v = new short[numCourses];
Deque<Integer> q = new ArrayDeque<>();
for(int i = 0; i < numCourses; i++){
if(inDegree[i] == 0){
q.offer(i);
}
}
List<Integer> tSortList = new ArrayList<>();
while(!q.isEmpty()){
int cur = q.poll();
tSortList.add(cur);
//System.out.println("cur = " + cur);
if(alMap.containsKey(cur)){
for(Integer d: alMap.get(cur)){
//System.out.println("d = " + d);
// if(v[d] == true){
// return true;
// }
inDegree[d]--;
if(inDegree[d] == 0){
q.offer(d);
}
}
}
}
return tSortList.size() == numCourses? false: true;
}
// inspired from - https://leetcode.com/problems/course-schedule/discuss/58730/Explained-Java-12ms-Iterative-DFS-solution-based-on-DFS-algorithm-in-CLRS
//0 -> White, -1 -> Gray, 1 -> Black
boolean hasCycleDFSIterative(int s, Map<Integer, List<Integer>> alMap, int [] colors){
Deque<Integer> stack = new ArrayDeque<>();
stack.push(s);
while(!stack.isEmpty()){
int cur = stack.peek();
if(colors[cur] == 0){
colors[cur] = -1;
if(alMap.containsKey(cur)){
for(Integer d: alMap.get(cur)){
if(colors[d] == -1){
return true;
}
if(colors[d] == 0){
stack.push(d);
}
}
}
}else if (colors[cur] == -1 || colors[cur] == 1){
colors[cur] = 1;
stack.pop();
}
}
return false;
}
boolean hasCycleDFS1(int s, Map<Integer, List<Integer>> alMap, int [] colors){
// if(v[s] == true){
// return true;
// }
colors[s] = -1;
if(alMap.containsKey(s)){
for(Integer d: alMap.get(s)){
//grey vertex
if(colors[d] == -1){
return true;
}
if(colors[d] == 0 && hasCycleDFS1(d, alMap, colors)){
return true;
}
}
}
colors[s] = 1;
return false;
}
// not efficient because we process black vertices again
boolean hasCycleDFS2(int s, Map<Integer, List<Integer>> alMap, boolean [] v){
// if(v[s] == true){
// return true;
// }
v[s] = true;
if(alMap.containsKey(s)){
for(Integer d: alMap.get(s)){
if(v[d] == true || hasCycleDFS2(d, alMap, v)){
return true;
}
}
}
v[s] = false;
return false;
}
}
Java version :
public class CycleDetection {
private List<ArrayList<Integer>> adjList = new ArrayList<>();
private boolean[] visited;
public static void main(String[] args) {
CycleDetection graph = new CycleDetection();
graph.initGraph(4);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
//graph.addEdge(1, 2);
graph.addEdge(2, 0);
graph.addEdge(2, 3);
//graph.addEdge(3, 3);
System.out.println(graph.isCyclic());
}
private boolean isCyclic() {
Stack<Integer> stack = new Stack<>();
//DFS
boolean[] recStack = new boolean[this.adjList.size()];
stack.add(0);//push root node
while (!stack.empty()) {
int node = stack.pop();
/*if (recStack[node]) {
return true;
}*/
visited[node] = true;
recStack[node] = true;
List<Integer> neighbours = this.adjList.get(node);
ListIterator<Integer> adjItr = neighbours.listIterator();
while (adjItr.hasNext()) {
int currentNode = adjItr.next();
if (!visited[currentNode]) {
visited[currentNode] = true;
stack.push(currentNode);
} else {
if (recStack[currentNode]) {
return true;
}
}
}
if (neighbours == null || neighbours.isEmpty())
recStack[node] = false;
}
return false;
}
private void initGraph(int nodes) {
IntStream.range(0, nodes).forEach(i -> adjList.add(new ArrayList<>()));
visited = new boolean[nodes];
}
private void addEdge(int u, int v) {
this.adjList.get(u).add(v);
}
}

Graphviz: arranging nodes

Is it possible to tell GraphViz (Dot) to try arranging nodes of the graph without stretching either of the dimensions?
For example, if I create a graph with 25 nodes and no edges, GraphViz visualizes it with all nodes in a single row. What I want is to get a 5 x 5 "field" of nodes.
rank=same in conjunction with invisible edges are your friend:
digraph Test
{
nodesep = 0.5; // even node distribution
node [ shape = circle, width = 0.7 ];
edge [ style = invis ];
{ rank = same; A; B; C; D; E }
{ rank = same; F; G; H; I; J }
{ rank = same; K; L; M; N; O }
{ rank = same; P; Q; R; S; T }
{ rank = same; U; V; W; X; Y }
C -> { F G H I J }
H -> { K L M N O }
M -> { P Q R S T }
R -> { U V W X Y }
}
Instead of the last four lines, you could simply use
A -> F -> K -> P -> U;
This would lead to the same result with the given nodes but may be less stable when node sizes are varying.
You can force the position of nodes in Graphviz although it won't work with the dot engine.
That means you will have to come up with an algorithm to specify the position of your node.
Look at this question: How to force node position (x and y) in graphviz
Alternatively you can use invisible edges:
nodeA -> nodeB [style=invis]
And create a mesh between your nodes, that would likely cause the engine to arrange the nodes in a orderly fashion.
In both cases you will have to specify how you want to arrange the nodes by either specifying their position or connecting them together.

Sort through list of nodes which have two dimensional properties

This is my Node class
public class Node
{
int Data= -1;
int X;
int Y;
Node LeftChild = null;
Node RightChild = null;
Node(int i)
{
this.Data = i;
}
}
This is my Inorder traversal code:
public static void inorder(Node current, int horiz_dist, int verti_dist)
{
if(current == null)
return;
inorder(current.LeftChild, ++horiz_dist, ++verti_dist);
horiz_dist--;
verti_dist--;
System.out.println("Node "+current.Data+": X = "+horiz_dist+", Y = "+verti_dist);
current.X = horiz_dist;
current.Y = verti_dist;
node_list.add(current);
inorder(current.RightChild, --horiz_dist, ++verti_dist);
horiz_dist++;
verti_dist--;
}
I have a list of nodes which I got from iterating a binary tree in Inorder traversal. Following is output from that traversal:
Node 18: X = 3, Y = 3
Node 7: X = 2, Y = 2
Node 5: X = 1, Y = 1
Node 12: X = 1, Y = 3
Node 9: X = 0, Y = 2
Node 13: X = -1, Y = 3
Node 6: X = 0, Y = 0
Node 8: X = -1, Y = 1
Node 10: X = -2, Y = 2
Node 15: X = -3, Y = 3
I want to sort All nodes based on X first (Decreasing order) and then Y (Increasing order). Where X and Y are the distance from the Root Node respectively. So final output will be:
Node 18: X = 3, Y = 3
Node 7: X = 2, Y = 2
Node 5: X = 1, Y = 1
Node 12: X = 1, Y = 3
Node 6: X = 0, Y = 0
Node 9: X = 0, Y = 2
Node 8: X = -1, Y = 1
Node 13: X = -1, Y = 3
Node 10: X = -2, Y = 2
Node 15: X = -3, Y = 3
EDIT: This is my comparator logic. I updated it. Now it worked
This is comparator logic I wrote:
`Collections.sort(node_list, new Comparator(){
public int compare(Node second, Node first)
{
if(first.X > second.X)
return 1;
else if(first.X < second.X)
return -1;
else if(first.X == second.X)
{
if(first.Y < second.Y)
return 1;
else if(first.Y > second.Y)
return -1;
else if( first.Y == second.Y)
return 0;
}
return 0;
}
});`
You can use std::sort with custom comparison function.
Let say you have a vector of Nodes std::vector<Node> vec then, You can use it like this
std::sort(vec.begin(), vec.end(), compare);
where compare is defined as below
bool compare(Node a, Node b)
{
if (a.X > a.X) return true;
if (a.Y > a.Y) return true;
}
running time for this algorithm is O(n*log(n))
Phew, let's try this again since I misunderstood the question originally. Since your whole goal is to assign these X/Y values through the process of tree traversal, first the bad news:
Recursive algorithms don't work here.
Whether you're using in-order or pre-order or post-order traversal, all of these algorithms fall apart since they want to dig their way down to the leaves recursively in a stack-like LIFO fashion (recursion uses the call stack like a LIFO structure). They would be fine if you wanted to output in a way sorted Y first then X, but not the other way around. To do X first is considerably trickier.
Pseudocode solution:
List<Node> current_row;
List<Node> next_row;
root_node.x = 0;
root_node.y = 0;
current_row.push(root_node);
// Right-to-Left, Top-to-Bottom
while (!current_row.empty())
{
do
{
Node node = current_row.pop();
// output node data
if (node.right_child)
{
node.right_child.x = node.x + 1;
node.right_child.y = node.y + 1;
next_row.push(node.right_child);
}
if (node.left_child)
{
node.left_child.x = node.x - 1;
node.left_child.y = node.y + 1;
next_row.push(node.left_child);
}
} while (!current_row.empty());
current_row.swap(next_row);
}
You can also use a single queue here but I thought this 'row-based' mentality might help you a bit more initially to understand what's going on.

Resources