我知道以前可以问过,但我找不到它。 我需要修改下面的dijkstra算法,它适用于查找 两个节点之间的最短路径,但我也需要找到所有可能的路径。 我知道这样做应该相对容易,但到目前为止我还没有想法 怎么做这个最简单的方法。我正在使用有向加权图。
class Dijkstra
{
private List<Node> _nodes;
private List<Edge> _edges;
private List<Node> _basis;
private Dictionary<string, double> _dist;
private Dictionary<string, Node> _previous;
public Dijkstra(List<Edge> edges, List<Node> nodes)
{
Edges = edges;
Nodes = nodes;
Basis = new List<Node>();
Dist = new Dictionary<string, double>();
Previous = new Dictionary<string, Node>();
// record node
foreach (Node n in Nodes)
{
Previous.Add(n.Name, null);
Basis.Add(n);
Dist.Add(n.Name, double.MaxValue);
}
}
/// Calculates the shortest path from the start
/// to all other nodes
public void calculateDistance(Node start)
{
Dist[start.Name] = 0;
while (Basis.Count > 0)
{
Node u = getNodeWithSmallestDistance();
if (u == null)
{
Basis.Clear();
}
else
{
foreach (Node v in getNeighbors(u))
{
double alt = Dist[u.Name] + getDistanceBetween(u, v);
if (alt < Dist[v.Name])
{
Dist[v.Name] = alt;
Previous[v.Name] = u;
}
}
Basis.Remove(u);
}
}
}
public List<Node> getPathTo(Node d)
{
List<Node> path = new List<Node>();
path.Insert(0, d);
while (Previous[d.Name] != null)
{
d = Previous[d.Name];
path.Insert(0, d);
}
return path;
}
public Node getNodeWithSmallestDistance()
{
double distance = double.MaxValue;
Node smallest = null;
foreach (Node n in Basis)
{
if (Dist[n.Name] < distance)
{
distance = Dist[n.Name];
smallest = n;
}
}
return smallest;
}
public List<Node> getNeighbors(Node n)
{
List<Node> neighbors = new List<Node>();
foreach (Edge e in Edges)
{
if (e.Origin.Equals(n) && Basis.Contains(n))
{
neighbors.Add(e.Destination);
}
}
return neighbors;
}
public double getDistanceBetween(Node o, Node d)
{
foreach (Edge e in Edges)
{
if (e.Origin.Equals(o) && e.Destination.Equals(d))
{
return e.Distance;
}
}
return 0;
}
public List<Node> Nodes
{
get { return _nodes; }
set { _nodes = value; }
}
public List<Edge> Edges
{
get { return _edges; }
set { _edges = value; }
}
public List<Node> Basis
{
get { return _basis; }
set { _basis = value; }
}
public Dictionary<string, double> Dist
{
get { return _dist; }
set { _dist = value; }
}
public Dictionary<string, Node> Previous
{
get { return _previous; }
set { _previous = value; }
}
}
}
static void Main(string[] args)
{
//Nodes initialisation goes here
Dijkstra d = new Dijkstra(_edges, _nodes);
d.calculateDistance(_dictNodes["A"]);
List<Node> path = d.getPathTo(_dictNodes["C"]);
}
答案 0 :(得分:3)
好的,我实际上已经修改了Dijkstra类来做BFS,它让我得到了所有可能的路线。我添加了这个方法:
public void BreadthFirst(Edge graph, LinkedList<String> visited)
{
LinkedList<String> nodes = graph.adjacentNodes(visited.Last());
// Examine adjacent nodes
foreach (String node in nodes)
{
if (visited.Contains(node))
{
continue;
}
if (node.Equals(endNode))
{
visited.AddLast(node);
printPath(visited);
visited.RemoveLast();
break;
}
}
// In breadth-first, recursion needs to come after visiting adjacent nodes
foreach (String node in nodes)
{
if(visited.Contains(node) || node.Equals(endNode))
{
continue;
}
visited.AddLast(node);
// Recursion
BreadthFirst(graph, visited);
visited.RemoveLast();
}
}
用法如下:
Dijkstra d = new Dijkstra(_edges, _nodes);
LinkedList<String> visited = new LinkedList<string>(); //collecting all routes
visited.AddFirst(start);
d.BreadthFirst(graph, visited);
答案 1 :(得分:2)
您无法轻易修改Dijkstra以显示所有可能的路径。您需要修改BFS或DFS搜索。
如果你试图修改Dijkstra,最后你将以BFS或DFS搜索算法结束,所以最好从那里开始。
答案 2 :(得分:1)
如果要查找所有简单路径,请使用修改后的BFS(您将记住使用的顶点,以便不在路径中重复它们)。甚至可能找不到所有路径(该过程不会终止(即它不是算法))。想象一下带有循环的图形,所有节点之间都存在无限路径(包含的循环数量不同......)
答案 3 :(得分:0)
以下是我在网上找到的一些算法,用于查找图表中的所有可能路径。他们不会修改Dijkstra的算法,但我认为他们应该做你想做的事。
来自https://mathoverflow.net/questions/18603/finding-all-paths-on-undirected-graph:
Suresh建议DFS,MRA指出,目前尚不清楚是否有效。这是我尝试在该评论主题之后的解决方案。如果图形具有从源s到目标t的m个边,n个节点和p个路径,则下面的算法以时间O((np + 1)(m + n))打印所有路径。 (特别是,需要O(m + n)时间才能注意到没有路径。)这个想法非常简单:进行详尽的搜索,但如果你已经陷入困境,请尽早保释。
如果没有提前退出,MRA的反例表明,即使p = 1,穷举搜索也花费Ω(n!)时间:节点t只有一个相邻边,而它的邻居是节点s,这是完整的一部分( sub)图Kn-1。
按下路径堆栈并调用搜索:
path // is a stack (initially empty)
seen // is a set
def stuck(x)
if x == t
return False
for each neighbor y of x
if y not in seen
insert y in seen
if !stuck(y)
return False
return True
def search(x)
if x == t
print path
seen = set(path)
if stuck(x)
return
for each neighbor y of x
push y on the path
search(y)
pop y from the path
此处搜索可以在DFS样式(如此处)或BFS样式中实现穷举搜索和卡住。
来自All possible paths in a cyclic undirected graph:
您可以使用DFS找到所有路径,例如| Vlad描述。要找到每个路径中出现的节点,您可以只维护一个布尔数组,说明到目前为止每个节点是否都出现在每个路径中。当您的DFS找到路径时,请遍历不在路径中的每个顶点,并将相应的数组值设置为false。完成后,只有值为true的顶点才会出现在每个路径中。
伪代码:
int source;
int sink;
int nVerts;
bool inAllPaths[nVerts]; // init to all true
bool visited[nVerts]; // init to all false
stack<int> path; // init empty
bool dfs(int u)
if (visited[u])
return;
if (u == sink)
for i = 0 to nVerts-1
if !stack.contains(i)
inAllPaths[i] = false;
return true;
else
visited[u] = true;
stack.push(u);
foreach edge (u, v)
dfs(v);
stack.pop();
visited[u] = false;
return false;
main()
dfs(source);
// inAllPaths contains true at vertices that exist in all paths
// from source to sink.
但是,这种算法效率不高。例如,在n个顶点的完整图形中(所有顶点都与所有其他顶点具有边缘),路径的数量将为n! (n阶乘)。
更好的算法是分别检查每个顶点的每个路径中是否存在。对于每个顶点,尝试找到从源到接收器的路径,而不必去往该顶点。如果找不到,那是因为顶点出现在每个路径中。
伪代码:
// Using the same initialisation as above, but with a slight modification
// to dfs: change the foreach loop to
foreach edge (u, v)
if (dfs(v))
return true; // exit as soon as we find a path
main()
for i = 0 to nVerts-1
set all visited to false;
if (inAllPaths[i])
visited[i] = true;
if (dfs(source))
inAllPaths[i] = false;
visited[i] = false;
不幸的是,在搜索路径时,这仍然是指数最坏的情况。您可以通过将搜索更改为广度优先搜索来解决此问题。如果我没弄错的话,这应该会给你O(VE)表现。
其他一些文章讨论了这个问题:
algorithm to enumerate all possible paths
Find all paths between two graph nodes
答案 4 :(得分:0)
这是使用 BFS 的方法:以下(GridLength
)函数(使用递归路径查找修改的 BFS < / em>两个节点之间的函数)可用于查找非循环图中的两个节点之间的所有可能路径:
python
例如,下图(DAG)G由给出
from collections import defaultdict
# modified BFS
def find_all_parents(G, s):
Q = [s]
parents = defaultdict(set)
while len(Q) != 0:
v = Q[0]
Q.pop(0)
for w in G.get(v, []):
parents[w].add(v)
Q.append(w)
return parents
# recursive path-finding function (assumes that there exists a path in G from a to b)
def find_all_paths(parents, a, b):
return [a] if a == b else [y + b for x in list(parents[b]) for y in find_all_paths(parents, a, x)]
如果我们要查找节点G = {'A':['B','C'], 'B':['D'], 'C':['D', 'F'], 'D':['E', 'F'], 'E':['F']}
和'A'
之间的所有路径(使用上面定义的函数作为'F'
,它将返回以下路径: