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();
    }
}
相关推荐
在繁华处1 小时前
Java从零到熟练(九):并发编程基础
java·开发语言
木头程序员1 小时前
SSM框架学习笔记
java·开发语言·mysql·spring·maven
李白你好1 小时前
页面资产梳理 · 技术指纹识别 · Spring 端点探测
java·后端·spring
一起逃去看海吧1 小时前
dify-03
java·linux·开发语言
我是一颗柠檬1 小时前
【Java后端技术亮点】热Key探测与本地缓存二级防护:Redis热点问题的终极解决方案
java·redis·后端·缓存·中间件
Refrain_zc2 小时前
Android 音视频通话核心 —— 音频编码(AAC)完整解析
java
xiaoshuaishuai82 小时前
C# AvaloniaUI 资源找不到报错
java·服务器·前端·windows·c#
Xin_ye100862 小时前
C# 零基础到精通教程 - 第十八章:部署与发布——让应用上线
开发语言·c#
我是唐青枫3 小时前
Java JdbcTemplate 实战指南:用 Spring 轻量完成数据库增删改查
java·数据库·spring
思麟呀3 小时前
C++11并发编程:call_once一次性执行+atomic原子类型+CAS无锁编程+自旋锁
linux·开发语言·jvm·c++·windows