Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Algorithm for removing fewest edges to force increase in length of shortest path in unweighted undirected graph

Given an adjacency matrix for an unweighted undirected graph, is there an efficient way (polynomial algorithm) to expand/increase the length of shortest path between any given two nodes s and t?

Example:

In the example below, there are 5 different 'shortest paths' from vertex s=1 to vertex t=5, each having length 3. I want to remove the fewest number of edges so that the shortest path length is forced to become 4 or more. (Disconnecting the graph is ok.)

Adjacency matrix (extended to correct the example):

 0 1 0 0 0 1 1 1 0 1 0 
 1 0 1 1 0 0 0 0 0 0 0  
 0 1 0 0 1 0 0 0 0 0 1 
 0 1 0 0 1 1 0 0 0 0 0  
 0 0 1 1 0 1 0 0 0 0 0 
 1 0 0 1 1 0 0 0 1 0 0 
 1 0 0 0 0 0 0 0 1 0 0 
 1 0 0 0 0 0 0 0 1 0 0 
 0 0 0 0 0 1 1 1 0 0 0
 1 0 0 0 0 0 0 0 0 0 1
 0 0 1 0 0 0 0 0 0 1 0 

representing this graph:

Modified graph (AKE)

Minimum cost for forcing the shortest path length to increase from 3 to 4 is the removal of two edges (1,2) and (5,9)

Goal:

Can you give any ideas for a general algorithm that finds the set of edges that must be removed in a general case?


Correction: As noted in my comments, this example is not complete. By adding two more vertices 10 and 11 (shown in red), the example is rescued.

like image 590
Alireza Farahani Avatar asked Jan 24 '13 07:01

Alireza Farahani


2 Answers

Input: G = (V,E), vertices s, t and positive integer d.

Question: Minimize the number of edges needed to delete such that dist(s,t) >= d.

This problem is NP-hard for d > 3 and polynomially solvable for other values of d.

The problem is FPT parameterized on the distance d and number of edges you are allowed to delete, k: The algorithm is as follows: Find an (s,t)-path of length at most d and branch on the d edges to which you can delete. This results in an algorithm which runs in time O(d^k * n^2).

It's para-NP-complete (resp. W[1]-hard) when parameterized by just d (resp. just k).

Ref: Paths of bounded length and their cuts: Parameterized complexity and algorithms, Golovach, P.A. and Thilikos, D.M., Discrete Optimization volume 8, number 1, pages 72 - 86, year 2011, publisher Elsevier.

like image 135
Pål GD Avatar answered Oct 29 '22 08:10

Pål GD


I solved it with an approach I mentioned in third comment of "Pål GD" answer. Here's the java code of that. Hope you find it helpful!

// BFS to find the depth of every node (from source node)
// graph is the adjacency matrix.
// elements of row zero and column zero are all useless. this program
// works with indices >=1 
private int[][] BFS (int[][] graph, int source, boolean SPedges){
    int[][] temp = null;

    // nodes is number of graph nodes. (nodes == graph.length - 1)
    if (SPedges){
        temp = new int[nodes + 1][nodes + 1];
    }
    else{
        depth[source] = 0;
    }
    LinkedList<Integer> Q = new LinkedList<Integer>();
    Q.clear();
    visited[source] = true;
    Q.addFirst(source);
    while (!Q.isEmpty()){
        int u = Q.removeLast();
        for (int k = 1; k <= nodes; k++){
            if (!SPedges){
                // checking if there's a edge between node u and other nodes
                if (graph[u][k] == 1 && visited[k] == false){
                    visited[k] = true;
                    depth[k] = depth[u] + 1;
                    Q.addFirst(k);
                }
            }
            else{
                if (graph[u][k] == 1 && depth[k] == depth[u] - 1){
                    Q.addFirst(k);
                    temp[k][u] = 1;
                }
            }
        }   
    }
    return temp;
}

// fills the edges of shortest path graph in flow 
private ArrayList<Edge> maxFlow(int[][] spg, int source, int sink){ 
    int u = source;
    ArrayList<Integer> path = new ArrayList<Integer> (depth[sink]);
    path.add(source);
    Arrays.fill(visited, false);
    visited[source] = true;
    for (int i = 1; i <= nodes + 1; i++){
        if (i == nodes + 1){
            if (u == source)
                break;
            u = path.get(path.size() - 2);
            i = path.remove(path.size() - 1);
        }
        else if(spg[u][i] == 1 && visited[i] == false){
            visited[i] = true;
            path.add(i);
            if (i == sink){
                for(int k = 0; k < path.size() - 1; k++){
                    spg[path.get(k)][path.get(k+1)] = 0;
                    spg[path.get(k+1)][path.get(k)] = 1;
                }
                i = 0;
                u = source;
                path.clear();
                path.add(u);
                Arrays.fill(visited, false);
            }
            else{
                u = i;
                i = 0;
            }
        }
    }

    LinkedList<Integer> Q = new LinkedList<Integer>();
    Q.clear();

    Arrays.fill(visited, false);

    visited[source] = true;
    Q.addFirst(source);
    while (!Q.isEmpty()){
        u = Q.removeLast();
        for (int k = 1; k <= nodes; k++){
            if (spg[u][k] == 1 && visited[k] == false){
                visited[k] = true;
                Q.addFirst(k);
            }   
        }
    }
    ArrayList<Edge> edges = new ArrayList<Edge>();
    for (int i = 1; i <= nodes; i++){
        for (int j = 1; j <= nodes; j++){
            if ((spg[i][j] == 1) && (visited[i] ^ visited[j])){
                edges.add(new Edge(i, j));
            }
        }
    }

    return edges;
}

public void Solv(){
    // adjacency matrix as g. represents the graph.
    // first we find depth of each node corresponding to source node by a BFS from source
    BFS(g, s, false);

    // shortest path length from source to sink (node t)
    SPL = depth[t];

    // shortest path graph
    // it's a subgraph of main graph consisting only edges that are in a shortest path
    // between s and t
    spg = BFS(g, t, true);

    // lastly we find edges of a min cut in shortest paths graph
    // and store them in "edges"
    edges = maxFlow(spg, s, t);
}    

class Edge{
    private int begin, end;
    public Edge(int begin, int end){
        this.begin = begin;
        this.end = end;
    }
    @Override
    public String toString() {
        return new String(String.valueOf(begin) + " " + String.valueOf(end));
    }
}
like image 28
Alireza Farahani Avatar answered Oct 29 '22 09:10

Alireza Farahani