Visit every Node of Graph in multitple "splited" paths - algorithm

Visit every Node of Graph in even Parts
Question
Given an undirected Graph G having n nodes and m edges (with weights). How do I get x Paths, that visit in total all edges m from a constant starting node and return in the end, of that path, to that starting node. Nodes can be visited more than once.
How do I write an algorithm to find those paths, that have the smallest maximum weight count. Secondly the total weight count should be minimized, but the most important part is that the highest weight count of one Path is as small as possible. The path should start from a given starting node and return after all times to that starting node.
Is this problem NP-Complete? (I think that it is, but I'm not sure and like to know why?)
I would be very happy about any help.
Example
Given this Graph with starting point 0 and x = 4
G = [(0, 2, w=1), (0, 8, w=1), (0, 6, w=1), (0, 4, w=1), (3, 2, w=1), (2, 1 w=1),
(1, 8, w=1), (8, 7, w=1), (7, 6, w=1), (6, 5, w=1), (5, 4, w=1), (4, 3, w=1)]
the best paths would be
([0, 6, 5, 4, 0], [0, 6, 7, 8, 0],
[0, 8, 1, 2, 0], [0, 2, 3, 4, 0])
because every path has a total weight count of 4. There are no path combinations where maximum total is smaller ...

Related

A* algorithm - Order of expanded nodes

I am wondering why the order of expansion is ACBDG and not just ACG. From what i understand from the A*-algorithm is that is uses the f-value, which is the heuristic value and the real cost combined to determine the next node to expand. Is is that when expanding a node, the previous cost will be the f-value from the next node and current node combined? Or the f-value of the next node and g-value from current node combined?
It seems strange that after expanding the A, C and B nodes that the next node would not be G, as H(G) is lower than H(D). I observe that the real cost is lower to D, but isnt the point of A* to go for the combined heuristic value and the actual cost?
The starting node is A and the goal is G
In the following steps to the left of the => are the unexpanded nodes, and on the right are the action and the result of the expansion. Nodes on the left contain between the parenthesis the path, the cost of that path, and heuristic value. On the right there is no heuristic value yet. Nodes on the left are sorted by cost of path + heuristic value, with later nodes added after the existing nodes if they have equal sums:
A(-, 7) => Expand A from -: got B(A, 1), C(A, 4)
C(A, 4, 2), B(A, 1, 6) => Expand C from A: got B(AC, 6), D(AC,
7), G(AC, 8)
B(A, 1, 6), G(AC, 8, 0), D(AC, 7, 2), B(AC, 6, 6) =>
Expand B from A: got C(AB, 3), D(AB, 5)
C(AB, 3, 2), D(AB, 5, 2), G(AC, 8, 0), D(AC, 7, 2), B(AC, 6, 6) => Expand C from AB: got D(ABC, 6), G(ABC, 7)
D(AB, 5, 2), G(ABC, 7, 0), G(AC, 8, 0), D(ABC, 6, 2), D(AC, 7, 2), B(AC, 6, 6) => Expand D from AB: got C(ABD, 8), G(ABD, 11)
G(ABC, 7, 0), G(AC, 8, 0), D(ABC, 6, 2), D(AC, 7, 2), C(ABD, 8, 2), G(ABD, 11, 0), B(AC, 6, 6) => Found G from ABC, end of search

kth largest element in range interval

Given a list of overlapping intervals of integers. I need to find the kth largest element.
Example:
List { (3,4), (2,8), (4,8), (1,3), (7,9) }
This interval represents numbers as
[3, 4], [2, 3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8], [1, 2, 3], and [7, 8, 9].
If we merge and sort it in decreasing order, we get
9, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 1
Now the 4th largest number in the list is 8.
Can anyone please explain an efficient (we don't have to generate the list) algorithm to find the kth element given only a list of internals ?
Find out the largest number. You go through intervals and examine ends of intervals. In your case it is 9. Set k = 1, and L = 9.
Perhaps there are other 9s. Mark (7,9) interval as visited and check if any other intervals contains 9 a >= 9 && b <= '. In your case there is only one 9.
Decrement current largest number (L -= L) and clear history of visited intervals. And repeat checking intervals.
Every time you meet your current largest number within an interval you should increment k and mark the interval as visited. As soon as it becomes equal to kth the current greatest number L is your answer.

Minimum Spanning Tree of weighted graph

I need to write a predicate that creates a minimum spanning tree of a weighted undirected graph, using Prim's Algorithm. This is what I have so far:
% call the recursive predicate with the list of all nodes and
% one element (in this case the last one).
mst(T) :- nodes(N), last(N,E), mst(T,N,E).
% The element E is added to the visited list and removed from the toVisit list.
mst(T,N,E) :- append(T,E,S), delete(R,E,L)...
Then the toVisit list should be sorted according to the distance of the edges connected to any of the nodes in the visited list. Any suggestions on how to do this?
So, first of all let's try to create a solution to find a spanning tree, not minimum, from wikipedia: "spanning tree T of an undirected graph G is a subgraph that is a tree which includes all of the vertices of G, with minimum possible number of edges" and "A tree is a connected undirected graph with no cycles. It is a spanning tree of a graph G if it spans G (that is, it includes every vertex of G) and is a subgraph of G (every edge in the tree belongs to G)". In this example, i consider a graph built in this way:
graph(ListOfVertices,ListOfEdges)
and each element of ListOfEdges is edge(X,Y,Cost).
Let's build a predicate that creates a tree (in this case a fully connected graph). make_kn_weighted/4 has as input the degree of each node (Size), the MinValue and MaxValue of edges's cost and creates the Graph in graph(LV,Comb).
make_kn_weighted(Size,MinValue,MaxValue,graph(LV,Comb)):-
Size1 is Size+1,
make_ordered_list(1,Size1,LV),
find_all_combinations_weighted(LV,MinValue,MaxValue,[],Comb).
make_ordered_list(Max,Max,[]):- !.
make_ordered_list(I,Max,[I|T]):-
I < Max,
I1 is I+1,
make_ordered_list(I1,Max,T).
find_all_combinations_weighted([_],_,_,C,C):- !.
find_all_combinations_weighted([H|T],Min,Max,CT,CO):-
find_combinations_weighted(H,T,Min,Max,C),
append(CT,C,C1),
find_all_combinations_weighted(T,Min,Max,C1,CO).
find_combinations_weighted(_,[],_,_,[]):- !.
find_combinations_weighted(E,[H|T],Min,Max,[edge(E,H,V)|TE]):-
random(Min,Max,V),
find_combinations_weighted(E,T,Min,Max,TE).
?- make_kn_weighted(4,2,7,G).
G = graph([1, 2, 3, 4], [edge(1, 2, 6), edge(1, 3, 6), edge(1, 4, 5), edge(2, 3, 4), edge(2, 4, 5), edge(3, 4, 5)]).
Then we crate a predicate that generates a spanning tree:
spanning_tree(graph([N|T],Edges),graph([N|T],TreeEdges)) :-
generate_spanning_tree(T,Edges,TreeEdgesUnsorted),
sort(TreeEdgesUnsorted,TreeEdges).
generate_spanning_tree([],_,[]).
generate_spanning_tree(Curr,Edges,[Edge|T]) :-
select(Edge,Edges,Edges1),
get_vertices(Edge,X,Y),
is_connected_to_tree(X,Y,Curr),
delete(Curr,X,Curr1),
delete(Curr1,Y,Curr2),
generate_spanning_tree(Curr2,Edges1,T).
get_vertices(edge(X,Y),X,Y).
get_vertices(edge(X,Y,_),X,Y).
is_connected_to_tree(X,Y,Ns):-
memberchk(X,Ns),
\+ memberchk(Y,Ns), !.
is_connected_to_tree(X,Y,Ns):-
memberchk(Y,Ns),
\+ memberchk(X,Ns).
So, obviously, both the spanning tree and the graph have the same vertices, and this is why i wrote graph([N|T],Edges),graph([N|T],TreeEdges). To generate the actual tree, firs we select a node from the list, with select/3 (in Edges1 we have all the elements from Edges without Edge. Then with get_vertices/3 we foud the two vertices connected by an edge. With is_connected_to_tree/3 we check if the two vertices are not already connected (in the list or remaining verices). Then we delete the two selected edges to the list of unconnected vertices (Curr) using two times delete/3 applied to Curr. Last call, the recursive call with parameters updated. Test:
?- make_kn(4,G), spanning_tree(G,T).
G = graph([1, 2, 3, 4], [edge(1, 2), edge(1, 3), edge(1, 4), edge(2, 3), edge(2, 4), edge(3, 4)]),
T = graph([1, 2, 3, 4], [edge(1, 2), edge(1, 3), edge(1, 4)]) ;
G = graph([1, 2, 3, 4], [edge(1, 2), edge(1, 3), edge(1, 4), edge(2, 3), edge(2, 4), edge(3, 4)]),
T = graph([1, 2, 3, 4], [edge(1, 2), edge(1, 3), edge(2, 4)])
and so on...
Now let's focus to Primm's algorthm: to adapt our predicate to generate the tree with minimum cost, we have, first of all sort the edges considering the cost of each edge, then we can call, as above, generate_spanning_tree/3. So, in prolog code:
mst_prim(graph([H|T],Edges),graph([H|T],TreeEdges),Cost):-
predsort(compare_edges_value,Edges,SortedEdges),
generate_spanning_tree(T,SortedEdges,TreeEdgesUnsorted),
sort(TreeEdgesUnsorted,TreeEdges),
sum_cost(TreeEdges,0,Cost).
compare_edges_value(O,edge(X1,Y1,C1),edge(X2,Y2,C2)):-
compare(O,C1+X1+Y1,C2+X2+Y2).
sum_cost([],C,C).
sum_cost([edge(_,_,C)|T],CT,Tot):-
CT1 is CT+C,
sum_cost(T,CT1,Tot).
predsort/3 sorts using compare_edge/3 to determine the order. sum_cost/3 simply sums the cost of every selected edge. Query:
make_kn_weighted(4,2,7,G), mst_prim(G,T,C).
G = graph([1, 2, 3, 4], [edge(1, 2, 3), edge(1, 3, 6), edge(1, 4, 6), edge(2, 3, 5), edge(2, 4, 2), edge(3, 4, 2)]),
T = graph([1, 2, 3, 4], [edge(1, 2, 3), edge(2, 4, 2), edge(3, 4, 2)]),
C = 7 ;
In backtracking, it generates all the spanning trees (if you don't want this behaviour, you can add a cut after calling generate_spanning_tree/2).

Flaw in this maximum clique polynomial time approach?

I have been trying to solve Maximum clique problem with the algorithm mentioned below and so far not been able to find a case in which it fails.
Algorithm:
For a given graph, each node numbered from 1 to N.
1. Consider a node as permanent node and form a set of nodes such that each node is connected to this permanent node.(the set includes permanent node as well)
2. Now form a subgraph of the original graph such that it contains all the nodes in the set formed and only those edges which are between the nodes present in the set.
3. Find degree of each node.
4. If all the nodes have same degree then we have a clique.
5. Else delete the least degree node from this subgraph and repeat from step 3.
6. Repeat step 1-5 for all the nodes in the graph.
Can anyone point out flaw in this algorithm?
Here is my code http://pastebin.com/tN149P9m.
Here's a family of counterexamples. Start with a k-clique. For each node in this clique, connect it to each node of a fresh copy of K_{k-1,k-1}, i.e., the complete bipartite graph on k-1 plus k-1 nodes. For every permanent node in the clique, the residual graph is its copy of K_{k-1,k-1} and the clique. The nodes in K_{k-1,k-1} have degree k and the other clique nodes have degree k - 1, so the latter get deleted.
Here's a 16-node counterexample, obtained by setting k = 4 and identifying parts of the K_{3,3}s in a ring:
{0: {1, 2, 3, 4, 5, 6, 7, 8, 9},
1: {0, 2, 3, 7, 8, 9, 10, 11, 12},
2: {0, 1, 3, 10, 11, 12, 13, 14, 15},
3: {0, 1, 2, 4, 5, 6, 13, 14, 15},
4: {0, 3, 7, 8, 9, 13, 14, 15},
5: {0, 3, 7, 8, 9, 13, 14, 15},
6: {0, 3, 7, 8, 9, 13, 14, 15},
7: {0, 1, 4, 5, 6, 10, 11, 12},
8: {0, 1, 4, 5, 6, 10, 11, 12},
9: {0, 1, 4, 5, 6, 10, 11, 12},
10: {1, 2, 7, 8, 9, 13, 14, 15},
11: {1, 2, 7, 8, 9, 13, 14, 15},
12: {1, 2, 7, 8, 9, 13, 14, 15},
13: {2, 3, 4, 5, 6, 10, 11, 12},
14: {2, 3, 4, 5, 6, 10, 11, 12},
15: {2, 3, 4, 5, 6, 10, 11, 12}}
What you propose looks very much like the following sorting algorithm combined with a greedy clique search:
Consider a simple undirected graph G=(V,E)
Initial sorting
Pick the vertex with minimum degree and place it first in the new list L. From the remaining vertices pick the vertex with minimum degree and place it in the second position in L. Repeat the operations until all vertices in V are in L.
Find cliques greedily
Start from the last vertex in L and move in reverse order. For each vertex v in L compute cliques like this:
Add v to the new clique C
Compute the neighbor set of v in L: N(v)
Pick the last vertex in N(v)
v=w; L=L intersection with N(v);
Repeat steps 1 to 4
Actually the proposed initial sorting is called a degeneracy ordering and decomposes G in k-cores (see Batagelj et al. 2002 ) A k-core is a maximal subgraph such that all its vertices have at least degree k. The initial sorting leaves the highest cores (with largest k) at the end. When vertices are picked in reverse order you are picking vertices in the highest cores first(similar to your step 4) and trying to find cliques there. There are a number of other possibilities to find cliques greedily based on k-cores but you can never guarantee an optimum unless you do full enumeration.
The proposed initial sorting is used, for example, when searching for exact maximum clique and has been described in many research papers, such as [Carraghan and Pardalos 90]

Can Hadoop's Shuffle/Sort (or partition) phase be customized to perform a graph traversal?

I am still learning about the MapReduce framework, specifically implemented by Hadoop, and I wonder if it can be modified to perform the following task:
The Map() function will emit (key,value) pairs, whose keys are arrays of size 2, say int[2].
I would like every pair containing any of the two integers in common to be mapped to the same reducer.
So for example, if Map() emits: ([2,3],4),([2,4],5),([6,5],2),([5,7],1), then Reduce1 should receive the first two pairs, and Reduce2 the second two (first two sharing 2, second two sharing 5).
This can be viewed as a connected component problem, where the vertices are the integers in the int[], and edges are shared between any two integers in the same int[].
A change in algorithm and you can probably achieve this - but you're going to need emit each edge twice
For each edge you currently output, you should output them for both vertex IDs, amend the outputted value to include the other edge, the weight and optionally a direction (if edge direction is important to your algorithm).
So instead of this:
([2,3],4)
([2,4],5)
([6,5],2)
([5,7],1)
Output this (S denotes the key was the source, D denotes the key was the destination):
(2, [3, 4, S])
(3, [2, 4, D])
(2, [4, 5, S])
(4, [2, 5, D])
(6, [5, 2, S])
(5, [6, 2, D])
(5, [7, 1, S])
(7, [5, 1, D])
Now in your reducer, you'll be grouping by the vertex ID, and will be able to iterate other the tuples containing the other vertex ID, a weight, and the direction:
(2, [3, 4, S])
(2, [4, 5, S])
(3, [2, 4, D])
(4, [2, 5, D])
(5, [6, 2, D])
(5, [7, 1, S])
(6, [5, 2, S])
(7, [5, 1, D])
You still need to be aware that each edge could potentially be processed twice, especially if the edges exist in both directions between two vertices.

Resources