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();
}
}