BFS Shortest Path Lemma 22.3 - graph

First the notation:
Let d[v] is a distance between root of the BFS tree and vertex v
This book states the following lemma:
During BFS the queue Q contains the vertices: v_1, v_2, ..., v_r, where
v_1 is the head of Q
v_r is the tail of Q
Then:
d[v_r] <= d[v_1] + 1
d[v_i] <= d[v_(i + 1)] for i = 1, 2, ..., r - 1
I do not understand first statement. In words it says: the last vertex v_r that BFS added to the queue has shorter distance to the root than the first vertex v_1 that we added to the queue. Visually:
root
/ \
v_1 v_2
/
v_3
/
v_r
How it can be possible?

You're misreading the statement.
d[v_r] <= d[v_1] + 1
means that the depth of v_r can be no greater than one more than the depth of v_1. v_r can be on the same level of the BFS tree or on the level below, but never farther than that. Relabeling your tree slightly,
root
/ \
v_a v_b
/
v_c
/
v_x
v_x can never be in the queue at the same time as v_a or v_b, but v_c can.
The only way d[v_r] could be less than d[v_1] is if you enqueued a previously-visited vertex.

Related

How can I calculate neighborhood overlap in weighted network?

How can I calculate neighborhood overlap between two nodes (i,j) in a weighted graph?
"...we define the neighborhood overlap of an edge connecting A and B to be the ratio: (number of nodes who are neighbors of both A and B)/ (number of nodes who are neighbors of at least one of A or B) where in the denominator we don’t count A or B themselves (even though A is a neighbor of B and B is a neighbor of A)."
https://www.cs.cornell.edu/home/kleinber/networks-book/networks-book-ch03.pdf
networkx has a built-in function to find the common neighbors of two nodes in a graph: common_neighbors. Now we only need to find the number of nodes that are neighbors to either A or B. Note that
| N(u) ⋃ N(v) | = |N(u)| + |N(v)| - | N(u) ⋂ N(v)|
where N(u) is the set of neighbors of u. Since we don't count A or B in the denominator, we need to subtract 2 from | N(u) ⋃ N(v) |.
def neighborhood_overlap(g, u, v):
n_common_nbrs = len(set(nx.common_neighbors(g, u, v)))
n_join_nbrs = g.degree(u) + g.degree(v) - n_common_nbrs - 2
return n_common_nbrs / n_join_nbrs
However, you still need to decide what happens if the denominator is 0, i.e., when the nodes A and B form a connected component of the graph.
I know the tag of the question is networkx, but since this is the first thing that pop ups on Google, on igraph the function would be
neighborhood_overlap <- function(g, node1, node2)
{
nh1 = neighborhood(graph=g, order=1, nodes=node1)[[1]]
nh2 = neighborhood(graph=g, order=1, nodes=node2)[[1]]
common = intersect(nh1, nh2)
commonl = length(common)
# | N(u) ⋃ N(v) | = |N(u)| + |N(v)| - | N(u) ⋂ N(v)|
union = degree(net_vc, v=node1) + degree(net_vc, v=node2) - commonl - 2
return(commonl/union)
}

Counting nodes and arcs in BFS Algorithm

In DFS you can count the elements by initializating two counters and incrementing them in the DFS-VISIT procedure(+1 node every time the procedure is called and +1 arc everytime that the adjacency list is explored). I was wondering How to obtain the same result in BFS.
This is the BFS pseudocode from Cormen's "Introduction to Algorithms", where G is the graph, s is the source node, d is the distance and π is the father node. How can i modify it to obtain the number of nodes and arcs in G?
BFS(G, s)
for each node u ∈ G.V - {s}
u.color = white
u.d = ∞
u.π = NIL
s.color = GRAY
s.d = 0
s.π = NIL
Q = Ø
ENQUEUE(Q, s)
while Q != Ø
u = DEQUEUE(Q)
for each v ∈ G.Adj[u]
if v.color == WHITE
v.color = GRAY
v.d = u.d + 1
v.π = u
ENQUEUE(Q, v)
u.color = BLACK
Well, both the adjacency list traversal and new vertex(node) discovery are done in the final while loop of your pseudocode. So, something like the modification given below could work.
numArcs = 0
numNodes = 0
while Q != Ø
u = DEQUEUE(Q)
numNodes += 1
for each v ∈ G.Adj[u]
numArcs += 1
if v.color == WHITE
v.color = GRAY
v.d = u.d + 1
v.π = u
ENQUEUE(Q, v)
u.color = BLACK
Note that if you want to count all the arcs, the incrementation of numArcs should be outside the scope of the if statement that follows it, as that if statement is only entered when the destination node is not previously enqueued.
Notice also that this algorithm gives only the number of arcs and nodes in the connected component including the starting node s. So, unless your BFS algorithm is modified to handle the case of the graph having multiple connected components, this algorithm will not find out all the nodes and arcs in a graph that is not connected.

Runtime Complexity | Recursive calculation using Master's Theorem

So I've encountered a case where I have 2 recursive calls - rather than one. I do know how to solve for one recursive call, but in this case I'm not sure whether I'm right or wrong.
I have the following problem:
T(n) = T(2n/5) + T(3n/5) + n
And I need to find the worst-case complexity for this.
(FYI - It's some kind of augmented merge sort)
My feeling was to use the first equation from the Theorem, but I feel something is wrong with my idea. Any explanation on how to solve problems like this will be appreciated :)
The recursion tree for the given recursion will look like this:
Size Cost
n n
/ \
2n/5 3n/5 n
/ \ / \
4n/25 6n/25 6n/25 9n/25 n
and so on till size of input becomes 1
The longes simple path from root to a leaf would be n-> 3/5n -> (3/5) ^2 n .. till 1
Therefore let us assume the height of tree = k
((3/5) ^ k )*n = 1 meaning k = log to the base 5/3 of n
In worst case we expect that every level gives a cost of n and hence
Total Cost = n * (log to the base 5/3 of n)
However we must keep one thing in mind that ,our tree is not complete and therefore
some levels near the bottom would be partially complete.
But in asymptotic analysis we ignore such intricate details.
Hence in worst Case Cost = n * (log to the base 5/3 of n)
which is O( n * log n )
Now, let us verify this using substitution method:
T(n) = O( n * log n) iff T(n) < = dnlog(n) for some d>0
Assuming this to be true:
T(n) = T(2n/5) + T(3n/5) + n
<= d(2n/5)log(2n/5) + d(3n/5)log(3n/5) + n
= d*2n/5(log n - log 5/2 ) + d*3n/5(log n - log 5/3) + n
= dnlog n - d(2n/5)log 5/2 - d(3n/5)log 5/3 + n
= dnlog n - dn( 2/5(log 5/2) - 3/5(log 5/3)) + n
<= dnlog n
as long as d >= 1/( 2/5(log 5/2) - 3/5(log 5/3) )

Prolog recursion simple explanation

I have the following recursion rules which returns the sum of a number, but I don't know how does it return the sum:
sum(1,1).
sum(A,Result) :-
A > 0,
Ax is A - 1,
sum(Ax,Bx),
Result is A + Bx.
now when you execute the following command in Prolog:
sum(3,X).
the answer will be 5, but as I look into the rules, I can't see how does these rules return values and sum the. How is the value of Bx is calculated ?
sum(3,X). actually gives a result of X = 6. This predicate (sum(N, X)) computes the sum of integers from 1 to N giving X:
X = 1 + 2 + 3 + ... + N.
So it is the sum of the integers from 1 to N.
sum(1,1) says the sum of 1 by itself is just 1. This is true. :)
The second clause should compute the sum for A > 1, but it's actually not totally properly written. It says A > 0 which is ignoring the fact that the first clause already takes care of the case for 1. I would have written it with A > 1. It will work as is, but be a little less efficient.
sum(A,Result) :-
A > 0,
Ax is A - 1,
sum(Ax, Bx), % Recursively find the sum of integers 1 to A-1
% Instantiate Bx with that sum
Result is A + Bx. % Result is A plus sum (in Bx) from 1 to A-1
This clause recursively says that the sum of integers from 1 to A is Result. That Result is the sum of A and the sum of integers from 1 to A-1 (which is the value Ax is unified to). The Bx is the intermediate sum of integers 1 through Ax (A-1). When it computes the sum(Ax, Bx), the value of Ax is 1 less than A. It will continue calling this second clause recursively until the first parameter goes down to 1, at which point the first clause will provide the value for the sum, and the recursion will unravel from there, summing 1, 2, 3, ...
EDIT: More Details on the Recursion
Let's look at sum(3,X) as an example.
sum(3,X) doesn't match sum(1,1). so that clause is skipped and Prolog looks at sum(A, Result). Prolog matches this by instantiating A as 3 and Result as X and steps through the statements making up the clause:
% SEQUENCE 1
% sum(A, Result) query issued with A = 3
3 > 1, % true
Ax is 3 - 1, % Ax is instantiated as the value 2
sum(2, Bx), % recursive call to `sum`, `Ax` has the value of 2
Result is 3 + Bx. % this statement is awaiting the result of `sum` above
At this point, Prolog suspends computing Result is A + Bx in order to make the recursive call. For the recursive call, Prolog can't match sum(Ax, Bx) to sum(1,1) because Ax is instantiated as 2. So it goes on to the next clause, sum(A, Result) and can match if it instantiates A as 2 and Result as Bx (remember, this is a new call to this clause, so these values for A and Result are a different copy than the ones we "suspended" above). Now Prolog goes through sum(A, Result) statements again, this time with the new values:
% SEQUENCE 2
% sum(A, Result) query issued with A = 2
2 > 0, % true
Ax is 2 - 1, % Ax is instantiated to the value 1
sum(1, Bx), % recursive call to `sum`, `Ax` has the value of 1
Result is 2 + Bx. % this statement is awaiting the result of `sum` above
Now Prolog has sum(1, Bx) (Ax is instantiated with 1). This will match sum(1,1) and instantiate Bx with 1 in the last query to sum above in SEQUENCE 2. That means Prolog will complete the sequence:
Result is 2 + 1. % `A` is 2 and `Bx` is 1, so `Result` is 3
Now that this result is complete, the recursive query to sum in the prior execution in SEQUENCE 1 will complete in a similar fashion. In this case, it is instantiated Bx with 3:
Result is 3 + 3. % `A` is 3 and `Bx` is 3 (from the SEQUENCE 2 query)
% so `Result` is 6
And finally, the original query, sum(3, X) completes, where X is instantiated with the result of 6 and you get:
X = 6.
This isn't a perfect explanation of how the recursion works, and there are some texts around with graphical representations that help. But I hope this provides some insight into how it operates.

how to find cryptarithmetic letter value?

Cross + roads = danger ==> the answer is ==> 96233 + 62513=158746
I'm looking for a instruction to find the answer easier for another example. one of my teacher said that we can using tree to find it. but sometimes using tree to find the answer is impossible.
How do you usually find you're cryptarithmetic solution?
One simple way :
Define the variables (just for convenience) :
vars = Symbol[#] & /# ("abc" <> ToString[#] & /# Range[26]) ;
Associate a variable to each letter of the alphabet :
alphabet = Transpose[{CharacterRange["a", "z"], vars}];
Write a helper function to translate a string into an expression :
formDigits[astring_] := FromDigits[alphabet[[alphabet[[#, 2]] & /#
Position[alphabet[[All, 1]], #][[1, 1]] & /# Characters[astring], 2]]]
Example :
formDigits["cross"]
(* abc19 + 10 (abc19 + 10 (abc15 + 10 (abc18 + 10 abc3))) *)
Write the system of equations corresponding to "Cross + roads = danger" :
equation = formDigits["cross"] + formDigits["roads"] == formDigits["danger"]
Finally solve the system with the obvious additional constraints :
sol = First#FindInstance[{equation, Sequence ## Thread[Thread[0 <= vars <= 9]],
Not[Apply[And, Thread[vars == 0]]]}, alphabet[[All, 2]], Integers] ;
Check :
formDigits["cross"] /. sol
formDigits["roads"] /. sol
formDigits["danger"] /. sol
(* 78644
86614
165258 *)
This is naturally solved, in Prolog. See also Faster implementation of verbal arithmetic in Prolog :
%% unique selection from narrowing domain
selectM([A|As],S,Z):- select(A,S,S1),selectM(As,S1,Z).
selectM([],Z,Z).
%% a puzzle
cryp([[C,R,O,S,S]+[R,O,A,D,S]=[D,A,N,G,E,R]]):-
Dom=[0,1,2,3,4,5,6,7,8,9],
selectM([S],Dom,D0),
N1 is S+S, R is N1 mod 10, R=\=0,
selectM([R,D],D0,D1), D=\=0,
N2 is (N1//10)+S+D, E is N2 mod 10,
selectM([E,O,A,G],D1,D2),
N3 is (N2//10)+O+A, G is N3 mod 10,
N4 is (N3//10)+R+O, N is N4 mod 10,
selectM([N,C],D2,_), C=\=0,
N5 is (N4//10)+C+R, A is N5 mod 10,
D is N5//10.
The key to efficiency is to choose the instantiations of digits progressively, one by one, testing right away to scrap the invalid choices as soon as possible. I'm sure this can be translated to Mathematica.
The other problem like this sum is
CROSS + ROADS = DENGER
The solution for this problem is
68244 + 82714 = 150958

Resources