去除最少边以强制增加无权无向图中最短路径长度的算法

2013-01-24 algorithm graph-theory graph-algorithm shortest-path

给定一个无权无向图的邻接矩阵,是否存在一种有效的方法(多项式算法)来扩展/增加任意给定两个节点s和t之间的最短路径的长度?

例:

在下面的示例中,从顶点s = 1到顶点t = 5共有5种不同的“最短路径”,每条路径的长度为3。更多。 (断开图表是可以的。)

邻接矩阵(扩展为更正示例):

 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 

表示此图:

修改图(AKE)

迫使最短路径长度从3增加到4的最小成本是移除两个边缘(1,2)和(5,9)

目标:

您能为找到一般情况下必须去除的边集的一般算法提供任何想法吗?


更正:如我的评论所述,此示例不完整。通过再添加两个顶点10和11(以红色显示),可以恢复该示例。

Answers

输入:G =(V,E),顶点s,t和正整数d。

问题:最小化删除所需的边数,以使dist(s,t)> = d。

对于d> 3,此问题是NP难的;对于d的其他值,此问题可以多项式求解。

问题是在距离d和允许删除的边数k上设置FPT参数,算法为k:算法如下:找到一条最长为d的(s,t)路径,并在要去除的d边上分支可以删除。这导致算法在时间O(d ^ k * n ^ 2)中运行。

仅用d(仅k)进行参数化时,它就是对NP完全的(W [1] -hard)。

参考:有限长度的路径及其切入:参数化的复杂度和算法,Golovach,PA和Thilikos,DM,离散优化第8卷,第1期,第72-86页,2011年,出版商Elsevier。

我用在“PålGD”答案的第三条评论中提到的方法解决了该问题。这是该代码的Java代码。希望对您有所帮助!

// 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));
    }
}

Related