Course Scheduling from Leetcode - graph

This is my solution to Course Scheduling Problem from leetcode. I am looking for any suggestions to improve my code, even slightest ones.
Here is the question:
There are a total of n courses you have to take, labeled from 0 to n-1.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.
There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.
Example 1:
Input: 2, [[1,0]]
Output: [0,1]
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1] .
Example 2:
Input: 4, [[1,0],[2,0],[3,1],[3,2]]
Output: [0,1,2,3] or [0,2,1,3]
Explanation: There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is [0,2,1,3].
Here is my solution:
class Solution:
def findOrder(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
#Convert prerequisites into an adjacency list
adj = []
for i in range(numCourses):
adj.append(set())
for pair in prerequisites:
adj[pair[0]].add(pair[1])
def DFSHelper(s):
visited.add(s)
stack.add(s)
for neighbor in adj[s]:
# if neighbor vertex has never been visted before, there is no way it could be a backedge.
# visit this unvisited vertex
if(neighbor not in visited):
if(not DFSHelper(neighbor)):
return False
Sorted.append(neighbor)
else:
if(neighbor in stack):
return False
stack.remove(s)
return True
visited = set()
stack = set()
Sorted = []
for j in range(len(adj)):
if(j not in visited):
if(not DFSHelper(j)):
print(j)
return []
Sorted.append(j)
return Sorted
I first converted given prerequisites list into an adjacency list representation of graph, then did topological sorting of the graph. I used DFS recursively to topologically sort the graph. The list Sorted stores the result of sorting. While doing DFS I also checked if the graph contains any cycle, if it does just return []. For purpose of checking cycle I maintained a set called stack that stores all the vertices that are currently in call stack.

This is a simple question first create a graph and then find topological sorting on nodes.
If topological order contains all nodes then we have our answer else not possible to finish all the courses.
class Solution {
public int[] findOrder(int n, int[][] prerequisites) {
List<Integer>[] g = new ArrayList[n];
for(int i = 0; i < n; i++)g[i] = new ArrayList();
int[] deg = new int[n];
for(int[] e: prerequisites) {
g[e[1]].add(e[0]);
deg[e[0]]++;
}
Queue<Integer> q = new LinkedList();
for(int i = 0; i < n; i++) {
if(deg[i] == 0)q.add(i);
}
int[] res = new int[n];
int idx = 0;
while(!q.isEmpty()) {
int u = q.poll();
res[idx++] = u;
for(int v: g[u]) {
deg[v]--;
if(deg[v] == 0) q.add(v);
}
}
return idx == n ? res: new int[0];
}}

Related

Loop for minimum spanning tree does not work

we as 3 friends try to solve minimum spanning tree with coflicts problem using r. In solving this question, we read files in .txt format that contain for ex.
"1 2 5
2 4 6" etc. which indicates from node 1 to 2, there exists an edge with weight 5 and
"1 2 2 4" etc. which indicates there's a conflict relationship between the edges 1-2 and 2-4. To continue, we have to form an nxn conflict matrix in which we will store 0's if there exist no conflict relation between the edges or 1 if there exist a conflict relation. For this purpose, we developed a 3-for loop for(i in 1:dim(edges_read)[1]){
for(i in 1:dim(edges_read)[1]){
for(k in 1:dim(edges_read)[1]){
for(t in 1:dim(conflicts)[1]){
if(all(conflicts[t,] == c(edges_read[i,1], edges_read[i,2],
edges_read[k,1], edges_read[k,2]) )){
conflictmatrix[i,k] <- 1
}
}
}
}
However, R cannot get us a solution and this for loops take very long times. How can we solve this situation? Thanks for further assistance
As you have discovered, for() loops are not fast in R. There are faster approaches, but it's hard to provide examples without data. Please use something like dput(edges_read) and dput(conflicts) to provide a small example of the data.
As one example, you could implement the for loops in the Rcpp package for speed improvement. Based on the code in your question, you could re-implement the 3-loop code sort of like this:
Rcpp::cppFunction('NumericVector MSTC_nxn_Cpp(NumericMatrix edges_read, NumericMatrix conflicts){
int n = edges_read.nrow(); //output matrix size (adjust to what you need)
int m = conflicts.nrow(); //output matrix size (adjust to what you need)
NumericMatrix conflictmatrix( n , m ); //the output matrix
for(int i=0;i<n;i++){ //your i loop
for(int k=0;k<n;k++){ // your k loop
double te = edges_read( i, 0 ); //same as edges_read[i,1]
double tf = edges_read( i, 1 ); //same as edges_read[i,2]
double tg = edges_read( k, 0 ); //same as edges_read[k,1]
double th = edges_read( k, 1 ); //same as edges_read[k,2]
NumericVector w = NumericVector::create(te,tf,tg,th); //this could probably be more simple
for(int t=0;t<m;t++){ //your t loop
NumericVector v = conflicts( t , _ ); // same as conflicts[t,]
LogicalVector r; //vector for checking if conflicts and edges are the same
for(int p=0; p<4; p++){ //loop to check logic
r[p]=v[p]==w[p]; //True / False stored
};
int q = r.size();
for (int ii = 0; ii < q; ++ii) { //similar to all() This code could be simplified!
if (!r[ii]) {false;}
else{conflictmatrix[i,k] = 1;}}
}}}
return conflictmatrix; //your output
}')
#Then run the function
MSTC_nxn_Cpp(edges_read, conflicts )

How to find a pair of numbers in a list given a specific range?

The problem is as such:
given an array of N numbers, find two numbers in the array such that they will have a range(max - min) value of K.
for example:
input:
5 3
25 9 1 6 8
output:
9 6
So far, what i've tried is first sorting the array and then finding two complementary numbers using a nested loop. However, because this is a sort of brute force method, I don't think it is as efficient as other possible ways.
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), k = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
Arrays.sort(arr);
int count = 0;
int a, b;
for(int i = 0; i < n; i++) {
for(int j = i; j < n; j++) {
if(Math.max(arr[i], arr[j]) - Math.min(arr[i], arr[j]) == k) {
a = arr[i];
b = arr[j];
}
}
}
System.out.println(a + " " + b);
}
}
Much appreciated if the solution was in code (any language).
Here is code in Python 3 that solves your problem. This should be easy to understand, even if you do not know Python.
This routine uses your idea of sorting the array, but I use two variables left and right (which define two places in the array) where each makes just one pass through the array. So other than the sort, the time efficiency of my code is O(N). The sort makes the entire routine O(N log N). This is better than your code, which is O(N^2).
I never use the inputted value of N, since Python can easily handle the actual size of the array. I add a sentinel value to the end of the array to make the inner short loops simpler and quicker. This involves another pass through the array to calculate the sentinel value, but this adds little to the running time. It is possible to reduce the number of array accesses, at the cost of a few more lines of code--I'll leave that to you. I added input prompts to aid my testing--you can remove those to make my results closer to what you seem to want. My code prints the larger of the two numbers first, then the smaller, which matches your sample output. But you may have wanted the order of the two numbers to match the order in the original, un-sorted array--if that is the case, I'll let you handle that as well (I see multiple ways to do that).
# Get input
N, K = [int(s) for s in input('Input N and K: ').split()]
arr = [int(s) for s in input('Input the array: ').split()]
arr.sort()
sentinel = max(arr) + K + 2
arr.append(sentinel)
left = right = 0
while arr[right] < sentinel:
# Move the right index until the difference is too large
while arr[right] - arr[left] < K:
right += 1
# Move the left index until the difference is too small
while arr[right] - arr[left] > K:
left += 1
# Check if we are done
if arr[right] - arr[left] == K:
print(arr[right], arr[left])
break

Algorithm to make a route from Source Node to End Node using every node exactly once

I'm trying to create a route, given a start node and end node, that will travel to every single node in the graph, and minimize the cost of doing so.
The graph is undirected, and every node is connected to each other directly. The weight of every edge is positive. I think because every node connects to eachother, that there are many "loops" in my graph, but I don't want to generate a route with a loop in it.
So, for a graph with N nodes, I have (N*N-1) directed edges. A graph with nodes A,B,C,D would have edges:
A to B / B to A
A to C / C to A
A to D / D to A
B to C / C to B
C to D / D to C
B to D / D to B
When I implement the Floyd Warshall algorithm from Wikipedia, I only ever get an array of 2 nodes. There's a function in the article that gives you the shortest path from node U to node V, and that's the function that only returns [U,V] (array containing U and V)
I MUST be misunderstanding what it is exactly that Floyd Warshall is meant to solve. I'll attach my code to show how I've implemented it in javascript.
function colorsToEdgeMatrix(colors){
var dist = [];
for(var i = 0; i < colors.length;i++){
dist[i] = [];
var c1 = colors[i];
for(var j = 0; j < colors.length;j++){
if(i == j){continue;}
var c2 = colors[j];
dist[i][j] = colorDistance(c1,c2);
}
}
return dist;
}
function colorsToNextMatrix(colors){
var next = [];
for(var i = 0; i < colors.length;i++){
next[i] = [];
for(var j = 0; j < colors.length;j++){
if(i == j){continue;}
next[i][j] = j;
}
}
return next;
}
//lab colors
function FloydWarshallWithPathReconstruction (colors){
var next = [];
var dist = colorsToEdgeMatrix(colors);
var next = colorsToNextMatrix(colors);
var N = colors.length;
for(var k = 0; k < N; k++){ // standard Floyd-Warshall implementation
for(var i = 0; i < N; i++){
for(var j = 0; j < N; j++){
if(dist[i][k] + dist[k][j] < dist[i][j]){
dist[i][j] = dist[i][k] + dist[k][j]
next[i][j] = next[i][k]
}
}
}
}
return next;
}
function Path(next,u, v) {
var path = [];
if(next[u][v] == null){
return []
}
path = [u]
while(u != v){
u = next[u][v]
path.push(u)
}
return path;
}
var lab = randomLABArray(100); //make an array of LAB color space colors. a LAB element has an array structure [L,a,b]
lab = sortLuminosityLAB(lab); //sorts the LAB colors from light to dark
var next = FloydWarshallWithPathReconstruction(lab); //gets all paths using floyd warshall
var path = Path(next, 0, lab.length-1); //gets the path calculated from lightest to darkest
console.log( path );
Does this algorithm not necessarily return a path that goes through every node? I guess what it does is just spits out the best path for every start and end node, and doesn't guarantee any path goes through every node...
I used the Nearest Neighbor algorithm with decent result, and Brute Force is impossible after 10 elements. I was hoping the Floyd Warshall would give even better results
Huh...so this might actually be a Hamiltonian Path problem and isn't as simple as I thought...
This can be reduced to the Traveling Salesman problem as follows. Pick a large number M which is greater than the sum of all weights in the graph. Add this number to the weights on all edges in the graph except the edge connecting the start node and the end node. That edge should have its cost set to zero. Solve the resulting Traveling Salesman Problem. It is easy to see that the optimal solution of the TSP will include the edge connecting the start and end node. Throw that edge away from the optimal solution and adjust the weights back to their original value -- and you have found the optimal solution to your problem.
Conversely, the regular TSP can be reduced to your problem in an even easier way. Pick a node at random and duplicate it. Let one of these newly duplicated nodes be the start node and the other be the end node. Solve your optimal path problem for this instance. Then -- remerge these two nodes into the original node, which will splice the ends together to form a circuit, which is easily seen to be optimal. This confirms your intuition that the problem is at least as hard as the Hamiltonian circuit problem.

Recognition of interval graphs

I need an algorithm for recognizing an interval graph and generate its intervals.
After some research I found the Algorithm developed by Wen-Lian Hsu.
(http://www.iis.sinica.edu.tw/IASL/webpdf/paper-1992-A_New_Test_for_Interval_Graphs.pdf).
It seems to be an algorithm, which solves my problem. But, I am not a computer scientist so I am having problems understanding the algorithm.
Could anybody explain this algorithm to a novice, plain and simple?
Having worked through some examples I think I know what is going on, though I still do not follow algorithm 4. My algorithm for determining if graphs are interval graphs is below followed by some Javascript code to implement the algorithm. Putting it in code allowed me to check whether it worked or not. The code can be found at this JSFiddle. I have tested the code with these three graphs. (1 and 2 are interval graphs 3 is not)
As I have made the algorithm from my interpretation of the paper given in my earlier answer I can give no guarantees that it is fully correct but it seems to work.
The algorithm will be worked through with graph 1
When x and y are vertices of the graph then x and y are neighbours when x and y are joined by an edge of the graph.
Algorithm for Interval Graphs.
Stage 1 create a Lexicographically Ordered list, L, of vertices from the graph.
Form an arbitrarily ordered list U of vertices of the graph, called a CLASS.
Form US, an ordered list of one element the class U.
While US is not empty
Take the 1st vertex, v, from the 1st class in US and put it at the front of L.
Set T to be an empty class
For each vertex in each class in US
If it is a neighbour of v remove it from its class and push to back of T
If T is not empty put T at front of US.
Remove any empty classes from US
L is now a Lexicographically Ordered list of vertices from the graph
For graph 1
U= (3,6,1,4,5,8,2,7)
US=( (3,6,1,4,5,8,2,7))
v=3 US=( (3,6,1,4,5,8,2,7)) L=(3)
neighbours of 3 to front
US=( (6,8),(1,4,5,2,7))
v=6 US=((8)(1,4,5,2,7)) L=(6,3)
neighbours of 6 to front
US=((8,1,7),(4,5,2))
v=8 US=((1,7)(4,5,2)) L=(8,6,3)
neighbours of 8 to front
US=((7,4,5,2)(1))
v=7 US=((4,5,2)(1)) L=(7,8,6,3)
neighbours of 7 to front
US=( (4,5)(2)(1))
v=4 US=((5)(2)(1)) L=(4,7,8,6,3)
neighbours of 4 to front
US=((5)(2)(1))
v=5 US=((2)(1)) L=(5,4,8,6,3)
neighbours of 5 to front – no neighbours so no change
US=((2)(1))
v=2 US=((1)) L=(2,5,4,8,6,3)
neighbours of 2 to front – no neighbours so no change
US=((1))
v=1 US=() L=(1,2,5,4,8,6,3)
L finished
Stage 2 – First test for an Interval Graph
When x is a vertex of the graph and L a lexicographical Ordered list of the graph
Set RN(x) to be the neighbours of x which come after x in L placed in the same order that they occur in L
Set parent(x) to be the first vertex in RN(x)
Set RNnoP(x) to be the vertices of in RN(x) with parent(x) removed, ie RN(x)/parent(x)
If the graph is an interval graph then for all vertices x if RNnoP(x) has any vertices in it then they will all appear in RN(parent(x)), ie RNnoP(x) is a subset of RN(parent(x)
If any x fails this test then the graph cannot be an interval graph.
Below shows the results for the example graph
x RN(x) Parent(x) RN(x)/parent(x) RN(parent(x)) Pass
1 | 6 | 6 | - | 3- | T
2 | 8 | 8 | - | 6- | T
5 | 7,8 | 7 | 8 | 8- | T
4 | 7,8 | 7 | 8 | 8- | T
7 |8 | 8 | - | 6- | T
8 | 6,3 | 6 | 3 | 3- | T
6 | 3 | 3 | - | -- | T
3 | - | - | - | -- | T
Stage 3 - for graphs that pass stage 2 form cliques for each vertex of the graph and create a set of maximal cliques
A CLIQUE is a set of vertices from the graph such that for any pair of different vertices in the set x,y then x and y are neighbours.
Set C(x) to be the set containing the vertices in RN(x) together with x, ie RN(x) Union {x}
Now it is necessary to form a set of maximal cliques. A clique is MAXIMAL if the addition on any other vertex into the clique stops it being a clique.
Using the parent relationships found in stage 2 form a tree
Using post-order traverse the tree and form a set, CS, of vertices where for each x in CS C(x) is a maximal clique using the following process on all vertices except for the root.
If C(parent(x)) is a subset of C(x)
if parent(x) in CS remove it
put x at in CS
Below is a tree for the example graph showing x and C[x] at each node
x RN(x) Parent(x) C(x) C(parent(x))
1 |6 | 6 | 1,6 | 3,6
2 Z8 | 8 | 2,8 | 3,6,8
5 |7,8 | 7 | 5,7,8 | 7,8
4 |7,8 | 7 | 4,7,8 | 7,8
7 |8 | 8 | 7,8 | 3,6,8
8 |6,3 | 6 | 3,6,8 | 3,6
6 |3 | 3 | 3,6 | 3
3 | - | - | 3 | -
The process on above tree
x=3 is root
x=6 C(6) = {3,6} CS=(6) C(3) is a subset of C(6) but 3 not in OC
x=1 C(1)={1,6} CS=(1,6) C(6) not a subset of C(1) put in 6
x=8 C(8)={3,6,8) CS=(1,8) C(6) is a subset of C(8) remove 6 put in 8
x=7 C(7)={7,8} ) CS=(1,8,7) C(8) not a subset of C(7) put in 7
x=4 C(4)={4,7,8} CS=(1,8,4) C(7) is a subset of C(4) remove 7 put in 4
x=5 C(5)={5,7,8} CS=(1,8,4,5) C(7) is a subset of C(5) but no 7, put in 5
x=2 C(2)={2,8} CS={1,8,4,5,2} C(8) is not a subset of C(2) put in 2
NOTE in the code I used a Children’s relationship to traverse the tree as a way of excluding the root.
Stage 4 Attempt to order the maximal cliques so that they are consecutive.
Cliques are in CONSECUTIVE order if for any vertex x, if x is in cliques n and n+m, m>0, the x is in cliques n+1, n+2, ……n+ m-1
The following algorithm will put the maximal cliques in consecutive order if it is possible to do so
Set NC to be the ordered list, or class, of maximal cliques from CS, such that if x is in CS(x) then C(x) is in NC
Set P to be the ordered list containing NC, P=(NC)
Set OC=() and empty ordered list
While P is not empty
Take the last clique, LST, from the last class of P and put at front of OC
For each clique Q in the last class of P partition into two classes
OUT if Q and LST have no vertices in common (intersection empty)
IN if Q and LST have vertices in common (non empty intersection)
Replace the last class of P with the classes OUT IN if both non empty
Replace the last class of P with the class OUT if OUT non empty and IN empty
Replace the last class of P with the classes IN if IN non empty and OUT empty
Leave P if both empty
For the example graph P=(({3,6,8},{4,7,8},{1,6},{5,7,8},{2,8})) (I have mixed up the order to show how the process works)
P=(({3,6,8},{4,7,8},{1,6},{5,7,8},{2,8})) OC=()
P=(({3,6,8},{4,7,8},{1,6},{5,7,8})) OC=({2,8})
OUT=({1,6}) IN=({3,6,8},{4,7,8},{5,7,8})
P=(({1,6}),({3,6,8},{4,7,8},{5,7,8})) OC=({2,8})
P=(({1,6}),({3,6,8},{4,7,8})) OC=({5,7,8},{2,8})
OUT=() IN({3,6,8},{4,7,8})
P=(({1,6}),({3,6,8},{4,7,8})) OC=({5,7,8},{2,8})
P=(({1,6}),({3,6,8})) OC=({4,7,8},{5,7,8},{2,8})
OUT=() IN({3,6,8})
P=(({1,6}),({3,6,8})) OC=({4,7,8},{5,7,8},{2,8})
P=(({1,6})) OC=({3,6,8},{4,7,8},{5,7,8},{2,8})
OUT=() IN=({1,6})
P=(({1,6})) OC=({3,6,8},{4,7,8},{5,7,8},{2,8})
P=(()) OC=({1,6},{3,6,8},{4,7,8},{5,7,8},{2,8})
P=()
NOTE in the code I have left NC = cliques as a list of vertices and used clique(label) for C(x)
Stage 5 check if OC is consecutively ordered
For each v in CS (as in stage 3)
For each vertex, x in C(v) the clique associated with v
If x is only in adjacent cliques in OC then
Interval graph
else
Not an interval graph
Stage 6 if past consecutive test draw intervals
Where n is the number of vertices determine n columns numbered 1 to n with gaps between them and equal width
For each v in CS with v first appearing in clique i and lastly in clique j 1=i<=j=n draw the interval from the start of column i to the end of column j
CODE IN JAVASCRIPT
Styles for Output of Intervals
.interval {
border-bottom: 1px solid black;
position: absolute
}
.label {
position:absolute;
}
Code
//Array methods added to carry out interval graph check
if(!Array.indexOf){ //Needed for earlier versions of IE;
Array.prototype.indexOf = function(obj){
for(var i=0; i<this.length; i++){
if(this[i]===obj){
return i;
}
}
return -1;
}
}
Array.prototype.subsetOf = function(set){ //returns true if Array is a subset of set
if(this.length==0) {return true;} //empty set is subset of all sets
var subset=true;
for(var i=0; i<this.length; i++){
subset = subset && (set.indexOf(this[i])>-1); //element of Array not in set forces subset to be false
}
return subset;
}
Array.prototype.intersection = function(set){ //returns the intersection of Array and set
if(this.length==0) {return [];} //empty set intersect any set is empty set
var inter=[];
for(var i=0; i<this.length; i++){
if(set.indexOf(this[i])>-1) {//element of Array and set
inter.push(this[i]);
}
}
return inter;
}
Array.prototype.union = function(set){ //returns the union of Array and set
var union=[];
for(var i=0; i<this.length; i++){
union.push(this[i]);
}
for(var i=0; i<set.length; i++) {
if(union.indexOf(set[i])==-1) {//element not yet in union
union.push(set[i]);
}
}
return union;
}
//A set is an array with no repeating elements
function vertex(label,neighbours) {
this.label=label;
this.neighbours=neighbours;
}
//Using the following format for each vertex on the graph [vertex lable, [neighbour lables] ] set up the model of the graph
//order of vertices does not matter
//graph One - an interval graph
graph=[
[3,[6,8]],
[6,[1,3,7,8]],
[1,[6]],
[4,[7,8]],
[5,[7,8]],
[8,[2,3,4,5,6,7]],
[2,[8]],
[7,[4,5,8]]
];
//graph Two - an interval graph
/*graph=[
['A',['B','C','D']],
['B',['A','C']],
['C',['A','B','D','E','F']],
['D',['A','C','E','F']],
['E',['C','D']],
['F',['D','G']],
['G',['F']]
];
//graph Three - not an interval graph
graph=[
['W',['Y','Z']],
['X',['Z']],
['Y',['W']],
['Z',['W']]
];
*/
/*Create a new vertex object U[i] where U is an unordered array.
*Unordered as at this point the numbering of vertices does not matter.
*Referencing by name rather than an array index is easier to follow
*/
var U=[];
for(var i=0; i<graph.length; i++) {
U[i]=new vertex(graph[i][0],graph[i][4]);
}
var US=[U];
/*US is an array containing the single array U
* during Lexicographical ordering US will contain other arrays
*/
//********************Lexicographical Ordering Start*************************
var L=[]; //L with contain the vertices in Lexicographical order.
while (US.length>0) {
F=US[0]; //First array in US
vertex=F.shift(); //In Javascript shift removes first element of an array
if(F.length==0) { //F is empty
US.shift();
}
L.unshift(vertex); //In Javascript unshift adds to front of array
var T=new Array(); //new array to add to front of US
tus=[]; //tempory stack for US sets
while(US.length>0) { //for remaining vertices in the arrays in US check if neighbours of vertex
set=US.shift(); //first set of US
ts=[]; //tempory stack for set elements
while(set.length>0){
v=set.shift(); //v is one of the remaining vertices //
lbl=v.label;
if (vertex.neighbours.indexOf(lbl) != -1) { //is v a neighbour of vertex
T.push(v); //push v to T
}
else {
ts.unshift(v); //not a neighbour store for return
}
}
while(ts.length>0) { //restore list of v not moved to set
set.push(ts.pop());
}
if(set.length>0) {//if set not empty store for restoration
tus.unshift(set);
}
}
if(T.length>0) { //if T not empty
US.push(T); //put T as first set of US
}
while(tus.length>0) {
US.push(tus.pop()); // restore non empty sets
}
}
//************************End of Lexicographical Ordering*************************
//----------------------Chordality Check and Clique Generation Start----------------------------------------
RN={}; //RN as an object so that an associative array can be used if labels are letters
Parent={}; //Parent as an object so that an associative array can be used if labels are letters
RNnoP={}; //RN with parent removed as an object so that an associative array can be used if labels are letters
Children={}; //Used in clique generation NOTE this is a deviation from given alogorithm 4 which I do not follow, again object for associative array
for(var i=0; i<L.length;i++) {
Children[L[i].label]=[];
}
var chordal=true;
for(var i=0; i<L.length-1; i++) {
vertex=L[i];
RN[vertex.label]=[];
RNnoP[vertex.label]=[];
for(j=i+1;j<L.length; j++) {
v=L[j];
lbl=v.label;
if(vertex.neighbours.indexOf(lbl) != -1) {
RN[vertex.label].push(lbl); //store vertex labels in order they are processed
}
}
Parent[vertex.label]=RN[vertex.label][0]; //Parent is front vertex of RN
Children[RN[vertex.label][0]].push(vertex.label);//used for Clique generation my method
for(k=1;k<RN[vertex.label].length;k++) {
RNnoP[vertex.label][k-1]=RN[vertex.label][k];
}
}
//************** chordality check ************
for(i=0; i<L.length-1; i++) {
vertex=L[i];
var x=vertex.label;
parentx=Parent[x];
for(j=0;j<RNnoP[x].length;j++) {
chordal = chordal && (RNnoP[x].subsetOf(RN[parentx]));
}
}
if(!chordal) {
alert('Not an Interval Graph');
}
else {
//Construct maximal clique list from tree formed by parent and child relationships determined above NOTE not algorithm 4
var root = Children[L[L.length-1].label]; //last vertex in L which has no parent
RN[L[L.length-1].label]=[]; //no vertices to right of last vertex
var clique={}; //clique for each vertex label -- object so associative array using lables
var cliques=[]; //stores maximal cliques from subtree of vertices processed
clique[L[L.length-1].label]=[L[L.length-1].label]; //clique for root contains last vertex label
generateCliques(root); //cliques becomes a list of labels of vertices with maximal cliques
var pivots=[];
for(i=0;i<cliques.length;i++) {
pivots=pivots.union(clique[cliques[i]]);
}
/*attempt to place each clique in cliques in consecutive order
* ie all cliques containing a given label are all next to each other
* if at end of process the cliques are in consecutive order then have an interval graph otherwise not an interval graph
*/
var orderedCliques=[]; //will contain maximal cliques in consecutive order if possible
var partitions=[cliques]; //holds partitions of cliques during process
while(partitions.length>0) {
inPartition=new Array(); //partition of elements containing pivot
outPartition=new Array(); //partition of elements not containing pivot
lastPartition=partitions.pop(); //last partition of cliques
orderedCliques.unshift(lastPartition.shift());//first label in partition moved to front of orderedCliques
pivotClique=clique[orderedCliques[0]]; //which points to pivot clique
for(var i=0; i<lastPartition.length; i++) {
if(pivotClique.intersection(clique[lastPartition[i]]).length>0){ //non empty intersection
inPartition=inPartition.union([lastPartition[i]]);
}
else {
outPartition=outPartition.union([lastPartition[i]]);
}
}
if(outPartition.length>0) {
partitions.push(outPartition);
}
if(inPartition.length>0) {
partitions.push(inPartition);
}
}
//----------------------End of Chordality Check and Clique Generation----------------------------------------
var start={}; //start is an associative array;
var end={}; //end is an associative array;
if (consecutive()){
//draw intervals......................
var across=20;
var down=20;
var colwidth=20;
var gap=30;
var coldepth=30;
var height=20;
for(v=0;v<pivots.length;v++) {
var vertex=pivots[v];
var line=document.createElement('div');
line.style.top=(down+(coldepth+height)*v)+'px';
line.style.height=(coldepth+height)+'px';
line.style.left=(across+start[vertex]*(colwidth+gap))+'px';
line.style.width=((end[vertex]-start[vertex])*gap+(1+end[vertex]-start[vertex])*colwidth)+'px';
line.className='interval';
document.body.appendChild(line);
var label=document.createElement('div');
label.style.left=line.style.left;
label.style.top=(parseInt(line.style.top)+28)+'px';
label.style.height='17px';
label.style.width='30px';
label.innerHTML=vertex;
label.className='label';
document.body.appendChild(label);
}
}
else {
alert('Not an Interval Graph')
};
}
function generateCliques(node) {
for(var i=0; i<node.length;i++) {
lbl=node[i];
clique[lbl]=[];
for(j=0;j<RN[lbl].length;j++) {
clique[lbl][j]=RN[lbl][j]; //each element of RN[x] becomes an element of clique[x]
}
clique[lbl].push(lbl); //RN(x) U {x} is a clique of subgraph processed so far and now clique[x] = RN[x] as sets
var parentx=Parent[lbl];
if(clique[parentx].subsetOf(clique[lbl])) {
var indx=cliques.indexOf(parentx);
if(indx>-1) { //if parent of lbl is in cliques list remove it
cliques.splice(indx,1);
}
}
cliques.push(lbl); //add lbl to cliques list
if(Children[lbl].length>0) { //lbl is not a leaf
generateCliques(Children[lbl]);
}
}
}
function consecutive() {
var p;
for(v=0;v<pivots.length;v++) {
var vertex=pivots[v];
p=0;
for(cl=0;cl<orderedCliques.length;cl++) {
if(clique[orderedCliques[cl]].indexOf(vertex)>-1) { //is vertex in maximal clique
if(p==0){
p=cl+1;
start[vertex]=p;
if(p==orderedCliques.length) {
end[vertex]=p;
}
}
else {
p+=1;
if(p==orderedCliques.length) {
end[vertex]=p;
}
if(p!=cl+1) {
return false;
}
}
}
else {
if(!end[vertex] && p>0) {
end[vertex]=cl;
}
}
}
}
return true;
}
This is not the full answer you are looking for but I hope it goes some way to helping.
Wikipedia led me to the *Interval Graph * page, on to the Lexicographic breadth-first search page on which I found the reference to the paper Habib, Michel; McConnell, Ross; Paul, Christophe; Viennot, Laurent (2000), "Lex-BFS and partition refinement, with applications to transitive orientation, interval graph recognition and consecutive ones testing",
Now this paper does give actual algorithms for determining if a graph is an integral graph using algorithms 2,3,4 and 9. Algorithms 2 and 3 can be found in alternative forms on the LBS page above and can be worked through. However so far, over the last couple of days, algorithm 4 has defeated me. Even working through the example graph they give does not produce the results they state.
So three possibilities.
I am not clever enough to understand it;
The algorithm is not sufficiently detailed;
There are mistakes in the algorithm.
Working on it being 2 or 3 that is true I will continue working on it on and off to see if I can crack it. Then there is algorithm 9 to tackle.
Perhaps the above pages and paper will give you enough insight into solving your problem. If I find a full answer I will post it. Good Luck.
For those who suffer from this paper like I do, I confirm that the algorithm 4 in the mentioned reference paper is weird/broken. Instead, I have found the second paper from the same authors about the same topics. You can check both papers here: http://citeseer.uark.edu:8080/citeseerx/showciting;jsessionid=B9CECB9E4B9DA156C687A414FA8743BF?cid=1681311
The second one appears to be written after a month and seems to be corrected by authors. I hope this may help someone now or later. In case the mentioned link will be unavailable ever, here are the 2 headings of the papers to search for:
Lex-BFS and Partition Refinement, with Applications to Transitive Orientation, Interval Graph Recognition and Consecutive Ones Testing.
Lex-BFS, a Partition Refining Technique. Application to Transitive Orientation, Interval Graph Recognition and Consecutive 1's Testing.
I have implemented the algorithms described in the second paper but it appears to have some bugs in the algorithm. I have met one of the authors (prof. Michel Habib) regarding to this, which required some more deep analysis. My implementation can be found here: https://github.com/Hack06/LexBFS

iterative version of easy recursive algorithm

I have a quite simple question, I think.
I've got this problem, which can be solved very easily with a recursive function, but which I wasn't able to solve iteratively.
Suppose you have any boolean matrix, like:
M:
111011111110
110111111100
001111111101
100111111101
110011111001
111111110011
111111100111
111110001111
I know this is not an ordinary boolean matrix, but it is useful for my example.
You can note there is sort of zero-paths in there...
I want to make a function that receives this matrix and a point where a zero is stored and that transforms every zero in the same area into a 2 (suppose the matrix can store any integer even it is initially boolean)
(just like when you paint a zone in Paint or any image editor)
suppose I call the function with this matrix M and the coordinate of the upper right corner zero, the result would be:
111011111112
110111111122
001111111121
100111111121
110011111221
111111112211
111111122111
111112221111
well, my question is how to do this iteratively...
hope I didn't mess it up too much
Thanks in advance!
Manuel
ps: I'd appreciate if you could show the function in C, S, python, or pseudo-code, please :D
There is a standard technique for converting particular types of recursive algorithms into iterative ones. It is called tail-recursion.
The recursive version of this code would look like (pseudo code - without bounds checking):
paint(cells, i, j) {
if(cells[i][j] == 0) {
cells[i][j] = 2;
paint(cells, i+1, j);
paint(cells, i-1, j);
paint(cells, i, j+1);
paint(cells, i, j-1);
}
}
This is not simple tail recursive (more than one recursive call) so you have to add some sort of stack structure to handle the intermediate memory. One version would look like this (pseudo code, java-esque, again, no bounds checking):
paint(cells, i, j) {
Stack todo = new Stack();
todo.push((i,j))
while(!todo.isEmpty()) {
(r, c) = todo.pop();
if(cells[r][c] == 0) {
cells[r][c] = 2;
todo.push((r+1, c));
todo.push((r-1, c));
todo.push((r, c+1));
todo.push((r, c-1));
}
}
}
Pseudo-code:
Input: Startpoint (x,y), Array[w][h], Fillcolor f
Array[x][y] = f
bool hasChanged = false;
repeat
for every Array[x][y] with value f:
check if the surrounding pixels are 0, if so:
Change them from 0 to f
hasChanged = true
until (not hasChanged)
For this I would use a Stack ou Queue object. This is my pseudo-code (python-like):
stack.push(p0)
while stack.size() > 0:
p = stack.pop()
matrix[p] = 2
for each point in Arround(p):
if matrix[point]==0:
stack.push(point)
The easiest way to convert a recursive function into an iterative function is to utilize the stack data structure to store the data instead of storing it on the call stack by calling recursively.
Pseudo code:
var s = new Stack();
s.Push( /*upper right point*/ );
while not s.Empty:
var p = s.Pop()
m[ p.x ][ p.y ] = 2
s.Push ( /*all surrounding 0 pixels*/ )
Not all recursive algorithms can be translated to an iterative algorithm. Normally only linear algorithms with a single branch can. This means that tree algorithm which have two or more branches and 2d algorithms with more paths are extremely hard to transfer into recursive without using a stack (which is basically cheating).
Example:
Recursive:
listsum: N* -> N
listsum(n) ==
if n=[] then 0
else hd n + listsum(tl n)
Iteration:
listsum: N* -> N
listsum(n) ==
res = 0;
forall i in n do
res = res + i
return res
Recursion:
treesum: Tree -> N
treesum(t) ==
if t=nil then 0
else let (left, node, right) = t in
treesum(left) + node + treesum(right)
Partial iteration (try):
treesum: Tree -> N
treesum(t) ==
res = 0
while t<>nil
let (left, node, right) = t in
res = res + node + treesum(right)
t = left
return res
As you see, there are two paths (left and right). It is possible to turn one of these paths into iteration, but to translate the other into iteration you need to preserve the state which can be done using a stack:
Iteration (with stack):
treesum: Tree -> N
treesum(t) ==
res = 0
stack.push(t)
while not stack.isempty()
t = stack.pop()
while t<>nil
let (left, node, right) = t in
stack.pop(right)
res = res + node + treesum(right)
t = left
return res
This works, but a recursive algorithm is much easier to understand.
If doing it iteratively is more important than performance, I would use the following algorithm:
Set the initial 2
Scan the matrix for finding a 0 near a 2
If such a 0 is found, change it to 2 and restart the scan in step 2.
This is easy to understand and needs no stack, but is very time consuming.
A simple way to do this iteratively is using a queue.
insert starting point into queue
get first element from queue
set to 2
put all neighbors that are still 0 into queue
if queue is not empty jump to 2.

Resources