LeetCode基础-图-有向图-最短路径

最短路径:从图中的一个顶点到另一个顶点的成本最小的路径。
单点最短路径:在加权有向图中,给出一个起点 s,找到是否有一条到顶点 v 的路径,如果有,找出权重最小的那条。

这里写图片描述

最短路径的性质:

  • 路径是有向的。
  • 权重不定表示距离。
  • 并不是所有顶点都是可达的。
  • 负权重会使问题变复杂。
  • 最短路径一般都是简单的(不含零权重边的环)。
  • 最短路径不定是唯一的。
  • 可能存在平行边和自环。平行边中权重最小的才会被选中。也不包含自环(除非自环的权重为零)

最短路径树(SPT):在加权有向图中,有一个顶点 s,以 s 为起点的最短路径树是图的一幅子图,包含 s 和从 s 到达的所有顶点。这棵树的根结点是 s,树的每条路径都是有向图中的一条最短路径。

这里写图片描述

加权有向边的数据结构:

public class DirectedEdge
{
    private final int v; // edge source
    private final int w; // edge target
    private final double weight; // edge weight

    public DirectedEdge(int v, int w, double weight)
    {
        this.v = v;
        this.w = w;
        this.weight = weight;
    }

    public double weight()
    { return weight; }

    public int from()
    { return v; }

    public int to()
    { return w; }

    public String toString()
    { return String.format("%d->%d %.2f", v, w, weight); }
}

加权有向图的数据结构:

public class EdgeWeightedDigraph
{
    private final int V; // number of vertices
    private int E; // number of edges
    private Bag<DirectedEdge>[] adj; // adjacency lists

    public EdgeWeightedDigraph(int V)
    {
        this.V = V;
        this.E = 0;
        adj = (Bag<DirectedEdge>[]) new Bag[V];
        for (int v = 0; v < V; v++)
        {
            adj[v] = new Bag<DirectedEdge>();
        }
    }

    public int V() { return V; }

    public int E() { return E; }

    public void addEdge(DirectedEdge e)
    {
        adj[e.from()].add(e);
        E++;
    }
    public Iterable<Edge> adj(int v)
    { return adj[v]; }

    public Iterable<DirectedEdge> edges()
    {
        Bag<DirectedEdge> bag = new Bag<DirectedEdge>();
        for (int v = 0; v < V; v++)
        {
            for (DirectedEdge e : adj[v])
            {
                bag.add(e);
            }
        }
        return bag;
    }
}

如下图:

这里写图片描述

最短路径的数据结构:

这里写图片描述

  • 最短路径树中的边:使用一个由顶点索引的DirectedEdge对象的父连接数组edgeTo[],edgeTo[v] 的值是树中连接 v 和它的父结点的边(也是 s 到 v 的最短路径上的最后一条边。edgeTo[s] = null;
  • 到达起点的距离:一个由顶点索引的数组 distTo[],其中 distTo[v] 是从 s 到 v 的已知最短路径的长度。distTo[s] = 0;

边的松驰(Relaxation)
定义:要放松(relax)一条边 v->w,意味着检查从
s 到 w 的最短路径是否是先从 s 到 v,然后从 v 到 w,如果是,则更新数据结构的内容。

private void relax(DirectedEdge e)
{
    int v = e.from();
    int w = e.to();
    if (distTo[w] > distTo[v] + e.weight())
    {
        distTo[w] = distTo[v] + e.weight();
        edgeTo[w] = e;
    }
}

边的松驰的两种情况:
一种是边失效,不更新数据。图左。
一种是 v -> w 就是到达 w 的最短路径。图右。

这里写图片描述

顶点的松驰(Relaxation)
顶点的松驰即是放松一个顶点的所有出边。

private void relax(EdgeWeightedDigraph G, int v) 
{
    for (DirectedEdge e : G.adj(v)) 
    {
        int w = e.to();
        if (distTo[w] > distTo[v] + e.weight()) 
        {
            distTo[w] = distTo[v] + e.weight();
            edgeTo[w] = e;
        }
    }
}

如下图:

这里写图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,prim算法并不能用于求解有向图最短路径,它只能用于求解无向的最小生成树。如果你想要求解有向图最短路径,可以使用Dijkstra算法或者Bellman-Ford算法。 Dijkstra算法是一种贪心算法,用于解决带权有向图或无向的单源最短路径问题,即给定中的一个源节点,找到该节点到中所有其他节点的最短路径。算法的基本思想是从源节点开始,依次选择当前距离源节点最近的一个节点,并通过该节点更新与它相邻的节点的距离。具体实现可以使用堆优化的Dijkstra算法,时间复杂度为O(ElogV)。 下面是一个使用Dijkstra算法求解有向图最短路径的Python代码示例: ```python import heapq def dijkstra(graph, start): # 初始化距离字典和堆 dist = {node: float('inf') for node in graph} dist[start] = 0 heap = [(0, start)] while heap: # 弹出堆中距离最小的节点 (d, node) = heapq.heappop(heap) # 如果该节点已经被访问过,则跳过 if d > dist[node]: continue # 遍历该节点的所有邻居节点 for neighbor, weight in graph[node].items(): # 计算从起点到该邻居节点的距离 new_dist = dist[node] + weight # 如果新的距离更短,则更新距离字典和堆 if new_dist < dist[neighbor]: dist[neighbor] = new_dist heapq.heappush(heap, (new_dist, neighbor)) return dist # 示例 graph = { 'A': {'B': 5, 'C': 1}, 'B': {'A': 5, 'C': 2, 'D': 1}, 'C': {'A': 1, 'B': 2, 'D': 4, 'E': 8}, 'D': {'B': 1, 'C': 4, 'E': 3, 'F': 6}, 'E': {'C': 8, 'D': 3}, 'F': {'D': 6} } # 求解从节点A到其他节点的最短路径 dist = dijkstra(graph, 'A') print(dist) # 输出:{'A': 0, 'B': 5, 'C': 1, 'D': 6, 'E': 9, 'F': 12} ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值