dijkstra单源最短路课设代码详解

115 篇文章 3 订阅
35 篇文章 4 订阅
/*朴素版dijkstra 时间复杂度最坏情况为O(n^2) 
dijkstra算法采用的是一种贪心的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。 
用一个dist数组保存源点到其余各点的距离,由于要求的时最短距离,所以初始化时,dist数组应该初始化为正无穷。
用一个标记数组st记录是否找到了源点到该节点的最短距离,如果st[i]为true,则表示找到了源点到节点i的最短距离。
如果为false,说明还没有找到,初始化数组st为false。 
实现过程:(伪代码) 
1.初始化all(dist[])=0x3f3f3f3f,dist[1]=0,S为已经确定最短距离的点的集合
2.for(int i=1;i<=n;i++)
{
    1. 寻找不在S中的距离最近的点t
    2. 将t加入到s中
    3. 用t更新其他点的距离 
}
*/
//1. 朴素版dijkstra之稠密图 
#include <bits/stdc++.h>
using namespace std;
const int N=510;
int g[N][N];//稠密图用邻接矩阵 
int dist[N];//dist[i]表示i到1节点的距离
bool st[N];//标记数组。如果i节点的距离已经被确定,则标记为true 
int n,m;//n个点m条边
int dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;//除1节点外,其余点设为正无穷
    for(int i=0;i<n;i++)//n次迭代,每次寻找不在s中距离最近的点t
    {
        int t=-1;//这里t的作用是为了便于更新第一个点,充当临时变量的作用。 
        for(int j=1;j<=n;j++)//循环遍历n个节点
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
                t=j;
        st[t]=true;//更新这个点之后就把他标记,也就是把他加入集合S中
        for(int j=1;j<=n;j++)//以t为跳板,更新t周围与之相邻的点 
            dist[j]=min(dist[j],dist[t]+g[t][j]); 
    }
    if(dist[n]==0x3f3f3f3f)return -1;//n没有被更新,即路径不存在。 
    else return dist[n]; 
}
int main()
{
    cout<<"请输入点的个数以及边的个数"<<endl;
    cout<<"点的个数n:"<<endl;
    cin>>n;
    cout<<"边的个数m: "<<endl;
    cin>>m;
    cout<<"请输入m条边:例如: a b c表示a->b边长为c"<<endl; 
    memset(g,0x3f,sizeof g);//初始化为正无穷表示两个点之间的距离还没有被更新
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        cout<<"请输入第 "<<i<<" 条边:"<<endl;
        cin>>a>>b>>c;
        g[a][b]=c;//a->b长度为c 
    }
    cout<<"1->n的距离是: ";
    cout<<dijkstra()<<endl;
    return 0; 
} 
//dijkstra之堆优化O(mlogn),主要用于稀疏图 
#include <bits/stdc++.h>
#define x first//方便写first和second,无其他含义 
#define y second
using namespace std;
const int N=510; 
int n,m;
int h[N],e[N],ne[N],w[N],idx; 
//h数组存头节点,e数组存节点编号,ne数组也就是next数组存后继节点,w数组存边权值
int dist[N];
bool st[N];
typedef pair<int,int>PII;
priority_queue<PII,vector<PII>,greater<PII>>heap;//小根堆,每次更新一次排序的情况是log的复杂度,相较于朴素版本的优化体现在这里。
void add(int a,int b,int c)// 链式前向星存图,可以理解为数组模拟单链表的尾插法。 a->b,权值为c。 
{
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
} 
int dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    heap.push({0,1});//{离起点的距离,点的编号}
    while(heap.size())
    {
        auto t=heap.top();//取堆顶元素,也就是离起点最近的点
        heap.pop();
        int ver=t.y;//节点
        int distance=t.x;//离起点的距离
        if(st[ver])continue;//如果被更新过,就看下一个点
        for(int i=h[ver];~i;i=ne[i])//遍历与ver相邻的点 
        {
            int j=e[i];//周围点为 j
            if(dist[j]>distance+w[i])
            {
                dist[j]=distance+w[i];//更新 
                heap.push({dist[j],j});//存入堆中 
            } 
        } 
    }
    if(dist[n]==0x3f3f3f3f)return -1;//不存在路径 
    else return dist[n];
}
int main()
{
    memset(h,-1,sizeof h);
    cout<<"请输入点的个数以及边的个数"<<endl;
    cout<<"点的个数n:"<<endl;
    cin>>n;
    cout<<"边的个数m: "<<endl;
    cin>>m;
    cout<<"请输入m条边:例如: a b c表示a->b边长为c"<<endl; 
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        cout<<"请输入第 "<<i<<" 条边:"<<endl;
        cin>>a>>b>>c;
        add(a,b,c);//a->b长度为c 
    }
    cout<<"1->n的距离是: ";
    cout<<dijkstra()<<endl;
    return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Dijkstra算法是一种用于计算图中单源最短路径的贪心算法。下面是Java实现Dijkstra算法的示例代码: ```java import java.util.*; public class DijkstraAlgorithm { private static final Graph.Edge[] GRAPH = { new Graph.Edge("A", "B", 7), new Graph.Edge("A", "D", 5), new Graph.Edge("B", "C", 8), new Graph.Edge("B", "D", 9), new Graph.Edge("B", "E", 7), new Graph.Edge("C", "E", 5), new Graph.Edge("D", "E", 15), new Graph.Edge("D", "F", 6), new Graph.Edge("E", "F", 8), new Graph.Edge("E", "G", 9), new Graph.Edge("F", "G", 11) }; private static final String START = "A"; private static final String END = "G"; public static void main(String[] args) { Graph graph = new Graph(GRAPH); graph.dijkstra(START); System.out.println(graph.getPath(END)); } static class Graph { private final Map<String, Vertex> graph; static class Edge { final String v1, v2; final int dist; Edge(String v1, String v2, int dist) { this.v1 = v1; this.v2 = v2; this.dist = dist; } } static class Vertex implements Comparable<Vertex> { final String name; int dist = Integer.MAX_VALUE; Vertex previous = null; final Map<Vertex, Integer> neighbours = new HashMap<>(); Vertex(String name) { this.name = name; } private void printPath() { if (this == this.previous) { System.out.printf("%s", this.name); } else if (this.previous == null) { System.out.printf("%s(unreached)", this.name); } else { this.previous.printPath(); System.out.printf(" -> %s(%d)", this.name, this.dist); } } public int compareTo(Vertex other) { return Integer.compare(dist, other.dist); } } Graph(Edge[] edges) { graph = new HashMap<>(edges.length); for (Edge e : edges) { if (!graph.containsKey(e.v1)) graph.put(e.v1, new Vertex(e.v1)); if (!graph.containsKey(e.v2)) graph.put(e.v2, new Vertex(e.v2)); } for (Edge e : edges) { graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist); } } void dijkstra(String startName) { if (!graph.containsKey(startName)) { System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName); return; } final Vertex source = graph.get(startName); NavigableSet<Vertex> q = new TreeSet<>(); for (Vertex v : graph.values()) { v.previous = v == source ? source : null; v.dist = v == source ? 0 : Integer.MAX_VALUE; q.add(v); } dijkstra(q); } private void dijkstra(final NavigableSet<Vertex> q) { Vertex u, v; while (!q.isEmpty()) { u = q.pollFirst(); if (u.dist == Integer.MAX_VALUE) break; for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) { v = a.getKey(); final int alternateDist = u.dist + a.getValue(); if (alternateDist < v.dist) { q.remove(v); v.dist = alternateDist; v.previous = u; q.add(v); } } } } List<String> getPath(String endName) { if (!graph.containsKey(endName)) { System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName); return Collections.emptyList(); } return graph.get(endName).printPath(); } } } ``` 该示例代码实现了一个简单的图,其中包含了一些边和顶点。在main方法中,我们创建了一个Graph对象,并调用了它的dijkstra方法来计算从起点到终点的最短路径。最后,我们打印出了这条路径。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leimingzeOuO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值