迪杰斯特拉算法dijkstra(单源最短路问题)(贪心)

本文详细介绍了最短路问题的解决方法,包括Dijkstra算法和Prim算法。Dijkstra算法适用于无负权边的图,对于稠密图采用邻接矩阵,稀疏图使用邻接表,通过贪心策略确定每个节点的最短路径。Prim算法则是寻找最小生成树,每次更新到集合的最短距离。在实现中,可以使用堆优化寻找最近的未确定节点,提高效率。此外,文章强调了建图策略和处理重边的重要性,并提供了相应的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最短路问题(有边权问题,无负权边,无权图就BFS即可 01边权使用双端队列BFS)

难点:抽象建图,如何把题意变为点和边。

  1. 无向图也是一种特殊的有向图,算法不变。
  2. 如果存在重边,必须保留最短的那条重边。
  3. 建图有两种方式,之前的文章已经有提过 (建图不用new,耗费时间长)
    1. 邻接表 :适合稀疏图 和 树 ( O mlogn)
    2. 邻接矩阵 :适合稠密图 (O n^2)
    3. 选择哪种方式则根据题目 给定数据范围推出。
  4. 由于dijk算法是基于贪心的算法,因此禁止负权边的出现。

  1. 稠密图 On^2: (n超过10万就超时)
    1. 问题定义: 求从1号点到其他所有点的最短距离

    2. 算法思路:(确定->更新)

      1. 初始化距离dist[1] = 0; else dist[i] = 0x3f3f3f3f;
      2. 集合dist: 当前已经确定的最短的点 (一旦确定,这个点的距离就不会再变)
      3. for (i 1~n) On
        1. for(j 1~n) t = 找到一个不在dist中,且距离1号点距离最近的点。On (prim算法这里更新的是到集合的最短距离)
        2. for(j 1~n) 用此点,来更新其他所有点到达1号点的距离 On
      4. 每次迭代都可以确定一个点,确定n此即确定所有点的最短距离
    3. 代码:

      Map[x][y] = Math.min(Map[x][y],z);  //这里一定要保存重边最小
      //----------------------------------------------
      static int dijkstra(){
          Arrays.fill(dist,0x3f3f3f);  //初始化为到不到的距离。
          dist[1] = 0;
          for(int i =0;i<n;i++){       //On  需要确定n个点。循环n次
              int t = -1;  //这个用于每次都能选择一个没有确定的点。 
              for(int j = 1;j<=n;j++){   //在没确定的点中,找到一个离起点最近的点。
                  if(st[j]==false && (t==-1 || dist[t] > dist[j])) t = j; //j还没有确定最短路。
              }
              st[t] = true;//然后这个点确定。dist[t]已经确定
              for(int j =1;j<=n;j++){  //借用此点更新其他点到1号点的距离  On
                  //On
                  dist[j] = Math.min(dist[j], dist[t] + Map[t][j]);
              }
          }
          if(dist[n]==0x3f3f3f)  return -1; //1 和 n 不连通。
       return dist[n];
      }
      

  1. 稀疏图 Omlogn (点多边少邻接表)
    1. 问题定义同上
    2. 算法思路同上:唯一优化的地方 就是确定离1号点最近的点使用堆来保存。Ologn
    3. 可以使用手写堆。也可以使用优先队列。(优先队列不能修改任意值,所以会存在很多冗余,修改一个就会添加一个,但是不影响使用)
    4. 代码
        static int dijkstra(){  //必背
            Arrays.fill(dist,0x3f3f3f3f);
            dist[1] = 0;
            PriorityQueue<Pair2> heap = new PriorityQueue<>();
            heap.add(new Pair2(0,1)); //1号点最短距离为0 pair(dist,num)
            while (!heap.isEmpty()){  //堆不空
                Pair2 pair = heap.poll(); //直接拿到堆中 最近的那个点。 
                int t = pair.num;  //提出此点
                int distance = pair.dist;
                if(st[t]==true) continue;  //已经确定了。就算堆里面还剩有也不会用了。 这里是核心。防止死循环。
                st[t] = true;//确定这个点
                for(int i = h[ver];i!=-1;i=NE[i]){  //遍历所有临边包括重边  Om
                    int j = E[i];
                    if(dist[j] > distance+w[i]){  // 如果到1号点距离变短了
                        dist[j] = distance + w[i];
                        heap.add(new Pair2(dist[j],j));//加就完事,无所谓上面有判断
                    }
                }
            }
            if(dist[n]==0x3f3f3f3f)  return -1; //1 和 n 不连通。
            return dist[n];
        }
        class Pair2{
        		int num;  //点的id;
        		int dist; //距离1号点的距离
        }
        ```
      
      
      
      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值