给定未加权无向图的邻接矩阵,是否有一种有效的方法(多项式算法)来扩展/增加任何给定的两个节点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)
目标:
您是否可以提供一般算法的任何想法,找到一般情况下必须删除的边集?
更正:如我的评论中所述,此示例未完成。通过添加另外两个顶点10和11(以红色显示),可以挽救该示例。
答案 0 :(得分:3)
输入:G =(V,E),顶点s,t和正整数d。
问题:最小化删除所需的边数,使得dist(s,t)> = d。
对于d>这个问题是NP难的。 3和多项式可解决其他d值。
问题是FPT参数化了距离d和允许删除的边数,k:算法如下:找到长度最多的(s,t)路径d和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年,出版商Elsevier。
答案 1 :(得分:2)
我用“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));
}
}