Procedure for reducing the density of a directed graph - algorithm

I have a complete weighted directed graph G=(V,A,W) and I want to reduce the density of the graph by deleting arcs as follows: given i,j,k \in V if w(i,j)+w(j,k) <= w(i,k), then we delete arc (i,k).
The code is given below, where ad is initially the adjacency matrix of G
for (int i = 0; i < |V|; ++i)
{
for (int j = 0; j < |V|; ++j)
{
if(j!=i)
{
for (int k = 0; k < |V|; ++k)
{
if(k!=i && k!=j){
if(ad[i][j]==1 && ad[j][k]==1 && w(i,j)+w(j,k) <= w(i,k))
ad[i][k]=0;
}
}
}
}
}
My question is: can this procedure make the resulting graph not connected?

Assuming no machine arithmetic shenanigans and that w(i, j) is positive whenever i ≠ j, no, you can't disconnect the graph.
For every (i, j) pair, consider a longest (by arc count) walk from i to j whose weight is at most w(i, j). This walk is well defined because i → j has weight at most w(i, j), and the assumptions of positive weights and a finite graph imply that the set of possible walks is finite, hence has a maximum. The algorithm cannot remove any of the arcs on this walk, or else there would be a longer walk. Hence the residual graph is strongly connected.

Related

Given nodes of a graph on a circle, find minimum number of nodes to be removed to have a graph in which each node has edge to its next node

Given n people sitting at the table, some of people are familiar with each other, familiarity is a bidirectional relation, find minimum number of people to be eliminated from the table in order to have a table that each person at the table is familiar with its neighbors. Give a solution of O(n^2)
My current effort:
As the order suggests, I tried solving the problem by T(n) = T(n-1) + O(n),
But if I consider I have found the ideal circle with m nodes envolving in it and now I want to add a new node, I check new node if it can be new member for the circle and make new circle of m+1 nodes, if it is possible then the problem is solved, but if it is not, I do need to store all circles of length m-1, m-2,... and add this new node to them which takes more than O(n) time.
Let assume that we have a graph with n nodes, 0 to n - 1.
If we view the problem as finding the shortest cycle from node A back to A, the distance between node a and b is the absolute different (b - a - 1) (which is all the nodes between those two) and we could only go from a to b if b > a or a is the start node. This problem is reduced to classic finding the shortest path in the graph.
Using Dijkstra algo, we could obtain a O(N^2 log N) algorithm.
Java code:
class State{
int node, distance;
}
int result = n - 1;
for(int i = 0; i < n; i++){
//Find the shortest path to move from i -> i
PriorityQueue<State> q = new PriorityQueue<>((a , b) -> Integer.compare(a.distance, b.distance));
for(int j : map[i]) {
if( j > i){
q.add(new State(j , j - i + 1);
}
}
int[]dist = new int[n];
Arrays.fill(dist, n - 1);
while(!q.isEmpty()){
State s = q.poll();
if(s.distance != dist[s.node]){
continue;
}
for(int j : map[s.node]){
if((j > s.node || j == i) && dist[j] > s.distance + (j - s.node + 1)){
dist[j] = s.distance + (j - s.node + 1);
q.add(new State(j, dist[j]);
}
}
}
result = Integer.min(result, dist[i]);
}

Path reconstruction - Pseudo-Multiply (Matrix multiplication) Algorithm

Context
I am currently working on path reconstruction in some of my graph algorithms. For the single-source-shortest-paths problem I used an array of predecessors to reconstruct the shortest path from one source node to all the other nodes.
Quick example:
[0, 3, 0, 0]
The shortest path from source 0 to target 1 would be [0, 3, 1] because starting from the target node 1 the path can be constructed by going backwards using the 'parent' array. 1 has been reached over 3 and 3 has been reached over 0. 0 is the source. Done.
The next algorithms are all-pairs-shortest-paths algorithms. The easiest example has been the Floyd-Warshall algorithm which results in a matrix containing all 'successor'-nodes. A good example for the reconstruction pseudo code can be found on Wikipedia - Floyd Warshall.
To summarize it: A matrix is used to store each successor from one specific source node. It basically follows the same approach as before just for each node as a source and going forward instead of backwards.
Question - How to create the matrix of successors in case of the pseudo multiply algorithm?
Let's have a look at the algorithm first:
for(int m = 0; m < nodeCount - 1; m++) {
Matrix nextResultMatrix = new Matrix(nodeCount, nodeCount, Integer.MAX_VALUE);
for(int i = 0; i < nodeCount; i++) {
for(int j = 0; j < nodeCount; j++) {
int value = Integer.MAX_VALUE;
for(int k = 0; k < nodeCount; k++) {
value = Math.min(
value,
resultMatrix.at(i, k) + sourceMatrix.at(k, j)
);
}
nextResultMatrix.setAt(i, j, value);
}
}
resultMatrix = nextResultMatrix;
}
In each iteration the matrix for the shortest paths of length m will be calculated. The inner loop is pretty similar to the matrix multiplication itself. In the most inner loop the algorithm checks wether the current path is shorter than the path from source i over k to target j. After the inner k-loop has finished the value inside of the new result matrix is set. Which leads to the problem:
In case of the Floyd-Warshall algorithm it was easier to identify wether the path has been shorter and which node is now the successor. In this case the value that has been calculated in the k-loop will be set anyway. Is it possible to determine the successor here?
Thoughts about a possible solution
The pseudo multiply algorithm provides a matrix for each iteration which represents the shortest paths of length m. Might this help to find a solution without increasing the - already quite bad - time complexity and without having to store each matrix at the same time.
I found an interesting idea in a comment here on stackoverflow which might lead to a solution reference. From what is stated there it seems to be quite heavy lifting for keeping track of the shortest paths. I haven't fully wrapped my head around the idea and how to implement this though.
My solution
So after stepping through the algorithm and making clear what each step exactly means I was finally able to figure out a solution. I will try to explain the changes in the code here but first let me present the solution:
for(int m = 0; m < nodeCount - 1; m++) {
Matrix nextResultMatrix = new Matrix(nodeCount, nodeCount, Integer.MAX_VALUE);
for(int i = 0; i < nodeCount; i++) {
for(int j = 0; j < nodeCount; j++) {
int value = resultMatrix.at(i, j);
int shorterPathFoundOverNode = prevMatrix.at(i, j);
// new shortest path from node i to j is
// the minimum path that can be found from node i over k to j
// k will be the node itself and every other node
for(int k = 0; k < nodeCount; k++) {
if(resultMatrix.at(i, k) != Graph.NO_EDGE && sourceMatrix.at(k, j) != Graph.NO_EDGE) {
if(value > resultMatrix.at(i, k) + sourceMatrix.at(k, j)) {
// update value if path is shorter
value = resultMatrix.at(i, k) + sourceMatrix.at(k, j);
shorterPathFoundOverNode = k;
}
}
}
nextResultMatrix.setAt(i, j, value);
prevMatrix.setAt(i, j, shorterPathFoundOverNode);
}
}
resultMatrix = nextResultMatrix;
}
A very basic but important idea was to replace the initialization value of value inside the j loop from Integer.MAX with the value that has previously been found or at first iteration the value that has been used to initialize the matrix (Integer.MAX). This was also important because the condition would have been true once per iteration which did not cause any problems before but now - since we perform more actions inside of the condition - it matters.
It was necessary to replace the Math.min method with an if condition to have the ability to do more than just setting the value.
To reconstruct the shortest paths the method of keeping track of the previous nodes is used. This is very similar to the single-source-shortest-paths problem as stated in the question. Of course it is required to use a matrix in this case because all nodes will be the source node.
To summarize the idea: Setup an additional matrix that keeps track of the previous node for each target node. When iterating through the k loop save the previous node if a shorter path has been found (Important: Only if it is actually shorter than the previous path).

Count triangles (cycles of length 3) in a graph

In an undirected graph with V vertices and E edges how would you count the number of triangles in O(|V||E|)? I see the algorithm here but I'm not exactly sure how that would be implemented to achieve that complexity. Here's the code presented in that post:
for each edge (u, v):
for each vertex w:
if (v, w) is an edge and (w, u) is an edge:
return true
return false
Would you use an adjacency list representation of the graph to traverse all edges in the outer loop and then an adjacency matrix to check for the existence of the 2 edges in the inner loop?
Also, I saw a another solution presented as O(|V||E|) which involves performing a depth-first search on the graph and when you encounter a backedge (u,v) from the vertex u you're visiting check if the grandparent of the vertex u is vertex v. If it is then you have found a triangle. Is this algorithm correct? If so, wouldn't this be O(|V|+|E|)? In the post I linked to there is a counterexample for the breadth-first search solution offered up but based on the examples I came up with it seems like the depth-first search method I outlined above works.
Firstly, note that the algorithm does not so much count the number of triangles, but rather returns whether one exists at all.
For the first algorithm, the analysis becomes simple if we assume that we can do the lookup of (a, b) is an edge in constant time. (Since we loop over all vertices for all edges, and only do something with constant time we get O(|V||E|*1). ) Telling whether something is a member of a set in constant time can be done using for example a hashtable/set. We could also, as you said, do this by the use of the adjacency matrix, which we could create beforehand by looping over all the edges, not changing our total complexity.
An adjacency list representation for looping over the edges could perhaps be used, but traversing this may be O(|V|+|E|), giving us the total complexity O(|V||V| + |V||E|) which may be more than we wanted. If that is the case, we should instead loop over this first, and add all our edges to a normal collection (like a list).
For your proposed DFS algorithm, the problem is that we cannot be sure to encounter a certain edge as a backedge at the correct moment, as is illustrated by the following counterexample:
A -- B --- C -- D
\ / |
E ----- F
Here if we look from A-B-C-E, and then find the backedge E-B, we correctly find the triangle; but if we instead go A-B-C-D-F-E, the backedges E-B, and E-C, do no longer satisfy our condition.
This is a naive approach to count the number of cycles.
We need the input in the form of an adjacency matrix.
public int countTricycles(int [][] adj){
int n = adj.length;
int count = 0;
for(int i = 0; i < n ;i++){
for(int j = 0; j < n; j++){
if(adj[i][j] != 0){
for(int k = 0; k < n; k++){
if(k!=i && adj[j][k] != 0 && adj[i][k] != 0 ){
count++;
}
}
}
}
}
return count/6;
}
The complexity would be O(n^3).

global mini-cut algorithm which outputs exact edges

I am looking for an algorithm to find global mini-cut in a undirected graph.
I want to input a graph and algorithm output minimum number of the edges by cutting them the given graph can be partitioned into two parts.
Here is requirement:
find exact edges, not only their number.
the min-cut edges should compute with 100% correctly.
it is an undirected graph.
the algorithm shall terminate by indicating it found the answer or not found the answer.
I searched some articles on Internet and find out that Karger's minimum cut algorithm is randomized one, its output maybe be not the exact min-cuts. I don't algorithm like that.
I want to compute exact edges(I need to know which edges they are) whose number is the smallest.
I would like to hear some advice, while I am looking for such algorithms.
It would be great if your advice comes with introduction to the algorithm with example codes.
Thanks in advance.
We can do this using max flow algorithm, when we calculate the max-flow of a graph the edges that are saturated when the algorithm finishes are part of the min-cut. You can read more about the Max flow Min cut theorem . Calculating the max flow is a fairly standard problem, there are a lot of polynomial time solutions available for that problem you can read more about them here.
So to summarize the algorithm, we first find the max flow of the graph, then the edges in the min cut are the ones where the flow on the edge is equal to the capacity of that edge (those edges that have been saturated).
So one of the ways to solve the max flow problem is using the Ford Fulkerson algorithm, it finds augmenting path in the graph, then using the minimum edge in the augmenting path tries to saturate that augmenting path, it repeats this process untill no augmenting path's are left.
To find the augmenting path we can either do a Depth first Search or a Breadth First Search. The Edmonds Karp's algorithm finds an augmenting path by using a simple Breadth first Search.
I have written c++ code below to find the max flow and min cut, the code to find max flow is taken from the book "Competetive Programming by Steven Halim".
Also note that since the graph is undirected all the edges that the min cut function print's would be twice as it prints a -- b and b -- a.
#include<iostream>
#include<vector>
#include<queue>
#include<utility>
#define MAXX 100
#define INF 1e9
using namespace std;
int s, t, flow, n, dist[MAXX], par[MAXX], AdjMat[MAXX][MAXX]; //Adjacency Matrix graph
vector< pair<int, int> > G[MAXX]; //adjacency list graph
void minCut(){
for(int i = 0;i < n;i++){
for(int j = 0;j < G[i].size();j++){
int v = G[i][j].first;
if(AdjMat[i][v] == 0){ //saturated edges
cout << i << " " << v << endl;
}
}
}
}
void augmentPath(int v, int minEdge){
if(v == s){ flow = minEdge;return; }
else if(par[v] != -1){
augmentPath(par[v], min(minEdge, AdjMat[par[v]][v]));
AdjMat[par[v]][v] -= flow; //forward edges
AdjMat[v][par[v]] += flow; //backward edges
}
}
void EdmondsKarp(){
int max_flow = 0;
for(int i= 0;i < n;i++) dist[i] = -1, par[i] = -1;
while(1){
flow = 0;
queue<int> q;
q.push(s);dist[s] = 0;
while(!q.empty()){
int u = q.front();q.pop();
if(u == t) break;
for(int i = 0;i < G[u].size();i++){
int v = G[u][i].first;
if(AdjMat[u][v] > 0 && dist[v] == -1){
dist[v] = dist[u] + 1;
q.push(v);
par[v] = u;
}
}
}
augmentPath(t, INF);
if(flow == 0) break; //Max flow reached, now we have saturated edges that form the min cut
max_flow += flow;
}
}
int main(){
//Create the graph here, both as an adjacency list and adjacency matrix
//also mark the source i.e "s" and sink "t", before calling max flow.
return 0;
}

Longest path in ordered graph

Let G = (V, E) be a directed graph with nodes v_1, v_2,..., v_n. We say that G is an ordered graph if it has the following properties.
Each edge goes from a node with lower index to a node with a higher index. That is, every directed edge has the form (v_i, v_j) with i < j.
Each node except v_n has at least one edge leaving it. That is, for every node v_i, there is at least one edge of the form (v_i, v_j).
Give an efficient algorithm that takes an ordered graph G and returns the length of the longest path that begins at v_1 and ends at v_n.
If you want to see the nice latex version: here
My attempt:
Dynamic programming. Opt(i) = max {Opt(j)} + 1. for all j such such j is reachable from i.
Is there perhaps a better way to do this? I think even with memoization my algorithm will still be exponential. (this is just from an old midterm review I found online)
Your approach is right, you will have to do
Opt(i) = max {Opt(j)} + 1} for all j such that j is reachable from i
However, this is exponential only if you run it without memoization. With memoization, you will have the memoized optimal value for every node j, j > i, when you are on node i.
For the worst case complexity, let us assume that every two nodes that could be connected are connected. This means, v_1 is connected with (v_2, v_3, ... v_n); v_i is connected with (v_(i+1), v_(i+2), ... v_n).
Number of Vertices (V) = n
Hence, number of edges (E) = n*(n+1)/2 = O(V^2)
Let us focus our attention on a vertex v_k. For this vertex, we have to go through the already derived optimal values of (n-k) nodes.
Number of ways of reaching v_k directly = (k-1)
Hence worst case time complexity => sigma((k-1)*(n-k)) from k=1 to k=n, which is a sigma of power 2 polynomical, and hence will result in O(n^3) Time complexity.
Simplistically, the worst case time complexity is O(n^3) == O(V^3) == O(E) * O(V) == O(EV).
Thanks to the first property, this problem can be solved O(V^2) or even better with O(E) where V is the number of vertices and E is the number of edges. Indeed, it uses the dynamic programming approach which is quiet similar with the one you gives. Let opt[i] be the length of the longest path for v_1 to v_i. Then
opt[i] = max(opt[j]) + 1 where j < i and we v_i and v_j is connected,
using this equation, it can be solved in O(V^2).
Even better, we can solve this in another order.
int LongestPath() {
for (int v = 1; v <= V; ++v) opt[v] = -1;
opt[1] = 0;
for (int v = 1; v <= V; ++v) {
if (opt[v] >= 0) {
/* Each edge can be visited at most once,
thus the runtime time is bounded by |E|.
*/
for_each( v' can be reached from v)
opt[v'] = max(opt[v]+1, opt[v']);
}
}
return opt[V];
}

Resources