Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8d4d810

Browse files
Merge pull request youngyangyang04#2856 from holic-x/master
docs:补充【0096-城市间货物运输III】JAVA版本的SPFA思路
2 parents 4d36947 + b5cbc15 commit 8d4d810

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

‎problems/kamacoder/0096.城市间货物运输III.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,125 @@ public class Main {
702702

703703
```
704704

705+
```java
706+
class Edge {
707+
public int u; // 边的端点1
708+
public int v; // 边的端点2
709+
public int val; // 边的权值
710+
711+
public Edge() {
712+
}
713+
714+
public Edge(int u, int v) {
715+
this.u = u;
716+
this.v = v;
717+
this.val = 0;
718+
}
719+
720+
public Edge(int u, int v, int val) {
721+
this.u = u;
722+
this.v = v;
723+
this.val = val;
724+
}
725+
}
726+
727+
/**
728+
* SPFA算法(版本3):处理含【负权回路】的有向图的最短路径问题
729+
* bellman_ford(版本3) 的队列优化算法版本
730+
* 限定起点、终点、至多途径k个节点
731+
*/
732+
public class SPFAForSSSP {
733+
734+
/**
735+
* SPFA算法
736+
*
737+
* @param n 节点个数[1,n]
738+
* @param graph 邻接表
739+
* @param startIdx 开始节点(源点)
740+
*/
741+
public static int[] spfa(int n, List<List<Edge>> graph, int startIdx, int k) {
742+
// 定义最大范围
743+
int maxVal = Integer.MAX_VALUE;
744+
// minDist[i] 源点到节点i的最短距离
745+
int[] minDist = new int[n + 1]; // 有效节点编号范围:[1,n]
746+
Arrays.fill(minDist, maxVal); // 初始化为maxVal
747+
minDist[startIdx] = 0; // 设置源点到源点的最短路径为0
748+
749+
// 定义queue记录每一次松弛更新的节点
750+
Queue<Integer> queue = new LinkedList<>();
751+
queue.offer(startIdx); // 初始化:源点开始(queue和minDist的更新是同步的)
752+
753+
754+
// SPFA算法核心:只对上一次松弛的时候更新过的节点关联的边进行松弛操作
755+
while (k + 1 > 0 && !queue.isEmpty()) { // 限定松弛 k+1 次
756+
int curSize = queue.size(); // 记录当前队列节点个数(上一次松弛更新的节点个数,用作分层统计)
757+
while (curSize-- > 0) { //分层控制,限定本次松弛只针对上一次松弛更新的节点,不对新增的节点做处理
758+
// 记录当前minDist状态,作为本次松弛的基础
759+
int[] minDist_copy = Arrays.copyOfRange(minDist, 0, minDist.length);
760+
761+
// 取出节点
762+
int cur = queue.poll();
763+
// 获取cur节点关联的边,进行松弛操作
764+
List<Edge> relateEdges = graph.get(cur);
765+
for (Edge edge : relateEdges) {
766+
int u = edge.u; // 与`cur`对照
767+
int v = edge.v;
768+
int weight = edge.val;
769+
if (minDist_copy[u] + weight < minDist[v]) {
770+
minDist[v] = minDist_copy[u] + weight; // 更新
771+
// 队列同步更新(此处有一个针对队列的优化:就是如果已经存在于队列的元素不需要重复添加)
772+
if (!queue.contains(v)) {
773+
queue.offer(v); // 与minDist[i]同步更新,将本次更新的节点加入队列,用做下一个松弛的参考基础
774+
}
775+
}
776+
}
777+
}
778+
// 当次松弛结束,次数-1
779+
k--;
780+
}
781+
782+
// 返回minDist
783+
return minDist;
784+
}
785+
786+
public static void main(String[] args) {
787+
// 输入控制
788+
Scanner sc = new Scanner(System.in);
789+
System.out.println("1.输入N个节点、M条边(u v weight)");
790+
int n = sc.nextInt();
791+
int m = sc.nextInt();
792+
793+
System.out.println("2.输入M条边");
794+
List<List<Edge>> graph = new ArrayList<>(); // 构建邻接表
795+
for (int i = 0; i <= n; i++) {
796+
graph.add(new ArrayList<>());
797+
}
798+
while (m-- > 0) {
799+
int u = sc.nextInt();
800+
int v = sc.nextInt();
801+
int weight = sc.nextInt();
802+
graph.get(u).add(new Edge(u, v, weight));
803+
}
804+
805+
System.out.println("3.输入src dst k(起点、终点、至多途径k个点)");
806+
int src = sc.nextInt();
807+
int dst = sc.nextInt();
808+
int k = sc.nextInt();
809+
810+
// 调用算法
811+
int[] minDist = SPFAForSSSP.spfa(n, graph, src, k);
812+
// 校验起点->终点
813+
if (minDist[dst] == Integer.MAX_VALUE) {
814+
System.out.println("unreachable");
815+
} else {
816+
System.out.println("最短路径:" + minDist[n]);
817+
}
818+
}
819+
}
820+
```
821+
822+
823+
705824
### Python
706825
```python
707826
def main():

‎problems/kamacoder/0097.小明逛公园.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,71 @@ floyd算法的时间复杂度相对较高,适合 稠密图且源点较多的
424424

425425
### Java
426426

427+
- 基于三维数组的Floyd算法
428+
429+
```java
430+
public class FloydBase {
431+
432+
// public static int MAX_VAL = Integer.MAX_VALUE;
433+
public static int MAX_VAL = 10005; // 边的最大距离是10^4(不选用Integer.MAX_VALUE是为了避免相加导致数值溢出)
434+
435+
public static void main(String[] args) {
436+
// 输入控制
437+
Scanner sc = new Scanner(System.in);
438+
System.out.println("1.输入N M");
439+
int n = sc.nextInt();
440+
int m = sc.nextInt();
441+
442+
System.out.println("2.输入M条边");
443+
444+
// 1 dp定义(grid[i][j][k] 节点i到节点j 可能经过节点K(k∈[1,n]))的最短路径
445+
int[][][] grid = new int[n + 1][n + 1][n + 1];
446+
for (int i = 1; i <= n; i++) {
447+
for (int j = 1; j <= n; j++) {
448+
for (int k = 0; k <= n; k++) {
449+
grid[i][j][k] = grid[j][i][k] = MAX_VAL; // 其余设置为最大值
450+
}
451+
}
452+
}
453+
454+
// 2 dp 推导:grid[i][j][k] = min{grid[i][k][k-1] + grid[k][j][k-1], grid[i][j][k-1]}
455+
while (m-- > 0) {
456+
int u = sc.nextInt();
457+
int v = sc.nextInt();
458+
int weight = sc.nextInt();
459+
grid[u][v][0] = grid[v][u][0] = weight; // 初始化(处理k=0的情况) 3 dp初始化
460+
}
461+
462+
// 4 dp推导:floyd 推导
463+
for (int k = 1; k <= n; k++) {
464+
for (int i = 1; i <= n; i++) {
465+
for (int j = 1; j <= n; j++) {
466+
grid[i][j][k] = Math.min(grid[i][k][k - 1] + grid[k][j][k - 1], grid[i][j][k - 1]);
467+
}
468+
}
469+
}
470+
471+
System.out.println("3.输入[起点-终点]计划个数");
472+
int x = sc.nextInt();
473+
474+
System.out.println("4.输入每个起点src 终点dst");
475+
476+
while (x-- > 0) {
477+
int src = sc.nextInt();
478+
int dst = sc.nextInt();
479+
// 根据floyd推导结果输出计划路径的最小距离
480+
if (grid[src][dst][n] == MAX_VAL) {
481+
System.out.println("-1");
482+
} else {
483+
System.out.println(grid[src][dst][n]);
484+
}
485+
}
486+
}
487+
}
488+
```
489+
490+
491+
427492
### Python
428493

429494
基于三维数组的Floyd

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /