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

Posted

技术标签:

【中文标题】去除最少边以强制增加未加权无向图中最短路径长度的算法【英文标题】:Algorithm for removing fewest edges to force increase in length of shortest path in unweighted undirected graph 【发布时间】:2013-01-07 21:45:30 【问题描述】:

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

示例:

在下面的示例中,从顶点 s=1 到顶点 t=5 有 5 条不同的“最短路径”,每个长度为 3。我想删除最少数量的边,以便强制最短路径长度变成4个或更多。 (断开图表是可以的。)

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

 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 

表示此图:

强制最短路径长度从 3 增加到 4 的最小成本是去除两条边 (1,2) 和 (5,9)

目标:

您能否给出一个通用算法的想法,该算法可以找到在一般情况下必须删除的边集?


更正:正如我在 cmets 中所指出的,此示例并不完整。通过再添加两个顶点 10 和 11(以红色显示),示例被救出。

【问题讨论】:

你试过什么?请为您描述的示例发布邻接矩阵(使我们不必考虑)。 @AKE 我已经编辑了问题。 哪些顶点是s和t? @ake 1 是源,5 是接收器 @AKE:我通过 max-flow min-cut theorem 解决了这个问题。答案是最小切割的边缘 【参考方案1】:

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

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

这个问题对于 d > 3 是 NP-hard 并且对于 d 的其他值是多项式可解的。

问题是在距离 d 和允许删除的边数 k 上参数化 FPT:算法如下:找到长度最多为 d 的 (s,t)-path 并在 d 边上分支可以删除的。这导致算法运行时间为 O(d^k * n^2)。

当仅由 d(或仅 k)参数化时,它是 para-NP-complete(或 W[1]-hard)。

参考:有界长度的路径及其切割:参数化复杂性和算法,Golovach,P.A.和 Thilikos, D.M.,离散优化第 8 卷,第 1 期,第 72 - 86 页,2011 年,出版商 E​​lsevier。

【讨论】:

能否请您参考一下您的来源? 这是个问题!我通过找到给定图的最大流量然后通过 BFS 找到最小切边来解决它。我会尽快发布我的答案。 @templatetypedef 添加了参考,他们将问题称为 BEUC,Bounded Edge Undirected (s,t)-cut。 @alireza 当且仅当您被允许删除的距离和边数都被认为是恒定的(假设 P != NP)时,该问题是多项式可解的。【参考方案2】:

我用我在“Pål GD”答案的第三条评论中提到的方法解决了这个问题。这是它的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));
    

【讨论】:

以上是关于去除最少边以强制增加未加权无向图中最短路径长度的算法的主要内容,如果未能解决你的问题,请参考以下文章

查找 NetworkX 中所有节点对之间的所有最短路径

在非加权图中找到最短路径

正加权有向无环图中的k-边最短路径

在加权图中找到最短路径

Python 图_系列之纵横对比 Bellman-Ford 和 Dijkstra 最短路径算法

C++ 图进阶系列之纵横对比 Bellman-Ford 和 Dijkstra 最短路径求解算法