Java中的图论3 —— Floyd

Java中的Floyd - 260331

  • [Floyd ------ 多源最短路](#Floyd —— 多源最短路)
  • [例题1(FROM 洛谷 B3647)](#例题1(FROM 洛谷 B3647))
  • [例题2 (FROM 洛谷 P2910)](#例题2 (FROM 洛谷 P2910))
  • 图论的总结
  • [图论提升 ------ 反向建图](#图论提升 —— 反向建图)

图论第一章 ->Java中的 Dijkstra 算法

图论第二章 ->Java中的图论2------Kruskal算法

图论第三章 -> 本章

Floyd ------ 多源最短路

如果说之前的 Dijkstra 算法是求最短路,那么 Floyd 算法就是求很多对点之间的最短路 ,但是他有个弊端,就是他是靠循环完成优化的,所以不可以在大数据情况下使用,如果数据很大,建议将Dijkstra封装成函数,多跑几次函数。

  • 原理:该算法的原理是,找图中是否有一个节点 k,使得节点 i 到节点 j ,经过节点 k 时比直接从 i 到 j 要 "近"(就是指总权重小)。

例题1(FROM 洛谷 B3647)

注意这里是 B3647,不是P3647。

代码实现

java 复制代码
import java.util.*;
public class Main{
    static int INF = 0x3f3f3f3f;
    public static void main(String [] args){
        Scanner input = new Scanner (System.in);
        int n = input.nextInt();
        int m = input.nextInt();
        int [][] dist = new int [n+1][n+1];
        for(int i=1;i<=n;i++)
           for(int j=1;j<=n;j++)
               dist[i][j] = (i==j)?0:INF;
        
        for(int i=0;i<m;i++){
            int u = input.nextInt();
            int v = input.nextInt();
            int w = input.nextInt();
           if(w<dist[u][v]){
               dist[u][v] = w;
               dist[v][u] = w;
           }
        }
 //------------------------------------------------ Floyd的核心循环------------------------------------------------------------------------------
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(dist[i][k] != INF && dist[k][j] != INF)
                        dist[i][j]=Math.min(dist[i][j],
                            dist[i][k]+dist[k][j]);
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        for(int i=1;i<=n;i++){
             for(int j=1;j<=n;j++)
                System.out.print(dist[i][j] + " ");
            System.out.println();
        }
    }
}

例题2 (FROM 洛谷 P2910)

代码实现

这个和之前的区别就多了一个累和

java 复制代码
import java.util.*;
public class Main{
    static int INF = 0x3f3f3f3f;
    public static void main(String [] args){
        Scanner input = new Scanner (System.in);
        int n = input.nextInt();
        int m = input.nextInt();
        int [] kk = new int [m+1];
        for(int i=0;i<m;i++)
            kk[i] = input.nextInt();
        int [][] dang = new int [n+1][n+1];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dang[i][j] = input.nextInt();
//---------------------------------------------------------------------------------------------------------核心循环------------------------------------------------------------------------------------------------------------------------
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(dang[i][j] != 0 && dang[i][j] != 0)
                        dang[i][j] = Math.min(dang[i][j],dang[i][k]+dang[k][j]);
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        long sum = 0;
        for(int i=0;i<m-1;i++)
            sum += dang[kk[i]][kk[i+1]];
        System.out.print(sum);
    }
}

图论的总结

  • Dijkstra 算法:
    解决问题:单源最短路(一个起点到所有点的最短距离)
    实现方式:最小堆(优先队列)+ BFS
  • Floyd 算法:
    解决问题:多源最短路(很多对点之间的最短路)
    实现方法:二维数组 + 三重循环
  • Kruskal 算法:
    解决问题:最小生成树/图(MST)
    实现方法:二维数组 + 并查集

图论提升 ------ 反向建图

思路

我最初的想法是用Floyd算法,预处理任意两点之间的最短距离,并用二维数组接收,但是这种方式的计算量是巨大的,并不适合本题。所以我又想到了Dijkstra算法,既然他属于单源最短路,我们可以用这个算法,但是他要一去一回,我们要使用两遍 Dijkstra ,所以我们将其封装成函数。同时,建一正一反两个图,同时处理,这样得到结果是最快的。

代码实现

java 复制代码
import java.util.*;
import java.io.*;

public class Main{
    static int n;
    static final long INF = (long) 1e15; 
    static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    
    public static void main(String [] args) throws IOException{
        n = Integer.parseInt(next());
        int m = Integer.parseInt(next());
        List<ArrayList<int []>> list1 = new ArrayList<>(n+1);
        List<ArrayList<int []>> list2 = new ArrayList<>(n+1);
        for(int i=0;i<=n;i++){
            list1.add(new ArrayList<>());
            list2.add(new ArrayList<>());
        }
        
        for(int i=0;i<m;i++){
            int u = Integer.parseInt(next());
            int v = Integer.parseInt(next());
            int w = Integer.parseInt(next());
            list1.get(u).add(new int []{v,w});//正图
            list2.get(v).add(new int []{u,w});//反图
        }
        
        long [] dist1 = dij(list1,1);
        long [] dist2 = dij(list2,1);
        long ans = 0;
        for(int i=2;i<=n;i++)
            ans += dist1[i] + dist2[i];
        System.out.print(ans);
    }
    static long [] dij(List<ArrayList<int []>> l,int begin){
        long [] dist = new long [n+1];
        Arrays.fill(dist,INF);
        dist [begin] = 0;
        PriorityQueue <long []> PQ = new PriorityQueue<>((a,b)->Long.compare(a[0],b[0]));
        PQ.offer(new long [] {dist[begin],begin});
        while(!PQ.isEmpty()){
            long [] cur = PQ.poll();
            long d = cur[0];
            int u = (int)cur[1];
            if(d!=dist[u]) continue;
            for(int [] e : l.get(u)){
                int v = e[0];
                int w = e[1];
                if(dist[u] + w < dist[v]){
                    dist[v] = dist[u] + w;
                    PQ.offer(new long[]{dist[v],v});
                }
            }
        }
        return dist;
    }
    static String next() throws IOException{
        while(st == null || !st.hasMoreTokens()){
            String str = bf.readLine();
            if(str == null) return null;
            st = new StringTokenizer(str);
        }
        return st.nextToken();
    }
}
相关推荐
We་ct3 分钟前
LeetCode 300. 最长递增子序列:两种解法从入门到优化
开发语言·前端·javascript·算法·leetcode·typescript
gCode Teacher 格码致知4 分钟前
Python提高: unittest和 pytest的使用方法-由Deepseek产生
开发语言·python·pytest
callJJ16 分钟前
JVM 类加载机制详解——从 .class 文件到对象诞生的完整旅程
java·jvm·类加载·双亲委派模型
Johnstons22 分钟前
网络可观测性落地指南:从“出了问题才排查“到“实时感知全网状态“
开发语言·网络·php
️是7828 分钟前
信息奥赛一本通—编程启蒙(3371:【例64.2】 生日相同)
开发语言·c++·算法
Kiling_070429 分钟前
Java Math类核心用法全解析
java·开发语言
踏着七彩祥云的小丑29 分钟前
开发中用到的注解
java
小梦爱安全32 分钟前
Ansible剧本1
java·网络·ansible
jieyucx32 分钟前
Go 语言运算符与控制台输入输出详解
开发语言·后端·golang
Ulyanov39 分钟前
《玩转QT Designer Studio:从设计到实战》 QT Designer Studio的定位革命与技术架构
开发语言·python·qt·系统仿真·雷达电子对抗仿真