Skip to content

Commit f6b12f0

Browse files
committed
modify code
1 parent daff692 commit f6b12f0

6 files changed

+88
-45
lines changed
50.1 KB
Binary file not shown.

src/class061/Code01_Kruskal.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.io.StreamTokenizer;
1515
import java.util.Arrays;
1616

17+
// 时间复杂度O(m * log m) + O(n + m)
1718
public class Code01_Kruskal {
1819

1920
public static int MAXN = 5001;
@@ -22,6 +23,7 @@ public class Code01_Kruskal {
2223

2324
public static int[] father = new int[MAXN];
2425

26+
// u, v, w
2527
public static int[][] edges = new int[MAXM][3];
2628

2729
public static int n, m;

src/class061/Code02_PrimDynamic.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.ArrayList;
1717
import java.util.PriorityQueue;
1818

19+
// 时间复杂度O(n + m) + O(m * log m)
1920
public class Code02_PrimDynamic {
2021

2122
public static void main(String[] args) throws IOException {
@@ -31,16 +32,23 @@ public static void main(String[] args) throws IOException {
3132
in.nextToken();
3233
int m = (int) in.nval;
3334
for (int i = 0, u, v, w; i < m; i++) {
34-
in.nextToken(); u = (int) in.nval;
35-
in.nextToken(); v = (int) in.nval;
36-
in.nextToken(); w = (int) in.nval;
35+
in.nextToken();
36+
u = (int) in.nval;
37+
in.nextToken();
38+
v = (int) in.nval;
39+
in.nextToken();
40+
w = (int) in.nval;
3741
graph.get(u).add(new int[] { v, w });
3842
graph.get(v).add(new int[] { u, w });
3943
}
44+
// int[] record
45+
// record[0] : 到达的节点
46+
// record[1] : 到达的花费
4047
PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[1] - b[1]);
4148
for (int[] edge : graph.get(1)) {
4249
heap.add(edge);
4350
}
51+
// 哪些节点已经发现过了
4452
boolean[] set = new boolean[n + 1];
4553
int nodeCnt = 1;
4654
set[1] = true;

src/class061/Code02_PrimStatic.java

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package class061;
22

3-
// Prim算法模版(洛谷)
3+
// Prim算法优化(洛谷)
44
// 静态空间实现
5+
// 时间复杂度O(n + m) + O((m+n) * log n)
56
// 测试链接 : https://www.luogu.com.cn/problem/P3366
67
// 请同学们务必参考如下代码中关于输入、输出的处理
78
// 这是输入输出处理效率很高的写法
@@ -15,10 +16,11 @@
1516
import java.io.StreamTokenizer;
1617
import java.util.Arrays;
1718

18-
// 以下的实现,即便是比赛也能通过
19-
// 建图用链式前向星、堆也是用数组结构手写的,不用任何动态结构
19+
// 建图用链式前向星
20+
// 堆也是用数组结构手写的、且只和节点个数有关
2021
// 这个实现留给有需要的同学
2122
// 但是一般情况下并不需要做到这个程度
23+
2224
public class Code02_PrimStatic {
2325

2426
public static int MAXN = 5001;
@@ -38,26 +40,26 @@ public class Code02_PrimStatic {
3840

3941
public static int cnt;
4042

41-
// 因为边的权重数据都在weight数组中
42-
// 所以需要比较边的权重,只需要有边的编号
43-
// 就可以从weight数组中拿出数据比较了
44-
// 所以小根堆只需要存储边的编号
45-
public static int[] heap = new int[MAXM];
43+
// 改写的堆结构
44+
public static int[][] heap = new int[MAXN][2];
4645

47-
public static int heapSize;
46+
// where[v] = -1,表示v这个节点,从来没有进入过堆
47+
// where[v] = -2,表示v这个节点,已经弹出过了
48+
// where[v] = i(>=0),表示v这个节点,在堆上的i位置
49+
public static int[] where = new int[MAXN];
4850

49-
// 节点有没有进入集合
50-
public static boolean[] set = new boolean[MAXN];
51+
// 堆的大小
52+
public static int heapSize;
5153

52-
// 一共有多少个点进入了集合
54+
// 找到的节点个数
5355
public static int nodeCnt;
5456

5557
public static void build() {
5658
cnt = 1;
5759
heapSize = 0;
5860
nodeCnt = 0;
5961
Arrays.fill(head, 1, n + 1, 0);
60-
Arrays.fill(set, 1, n + 1, false);
62+
Arrays.fill(where, 1, n + 1, -1);
6163
}
6264

6365
public static void addEdge(int u, int v, int w) {
@@ -67,41 +69,70 @@ public static void addEdge(int u, int v, int w) {
6769
head[u] = cnt++;
6870
}
6971

70-
// 编号为e的边进入小根堆,根据边的权重来组织小根堆
71-
public static void push(int e) {
72-
int i = heapSize++;
73-
heap[i] = e;
74-
while (weight[heap[i]] < weight[heap[(i - 1) / 2]]) {
72+
// 当前处理的是编号为ei的边!
73+
public static void addOrUpdateOrIgnore(int ei) {
74+
int v = to[ei];
75+
int w = weight[ei];
76+
// 去往v点,权重w
77+
if (where[v] == -1) {
78+
// v这个点,从来没有进入过堆!
79+
heap[heapSize][0] = v;
80+
heap[heapSize][1] = w;
81+
where[v] = heapSize++;
82+
heapInsert(where[v]);
83+
} else if (where[v] >= 0) {
84+
// v这个点的记录,在堆上的位置是where[v]
85+
heap[where[v]][1] = Math.min(heap[where[v]][1], w);
86+
heapInsert(where[v]);
87+
}
88+
}
89+
90+
public static void heapInsert(int i) {
91+
while (heap[i][1] < heap[(i - 1) / 2][1]) {
7592
swap(i, (i - 1) / 2);
7693
i = (i - 1) / 2;
7794
}
7895
}
7996

80-
// 小根堆中弹出权重最小的边的编号
81-
public static int pop() {
82-
int e = heap[0];
83-
heap[0] = heap[--heapSize];
84-
int i = 0;
97+
public static int u;
98+
99+
public static int w;
100+
101+
// 堆顶的记录:节点 -> u、到节点的花费 -> w
102+
public static void pop() {
103+
u = heap[0][0];
104+
w = heap[0][1];
105+
swap(0, --heapSize);
106+
heapify(0);
107+
where[u] = -2;
108+
nodeCnt++;
109+
}
110+
111+
public static void heapify(int i) {
85112
int l = 1;
86113
while (l < heapSize) {
87-
int best = l + 1 < heapSize && weight[heap[l + 1]] < weight[heap[l]] ? l + 1 : l;
88-
best = weight[heap[best]] < weight[heap[i]] ? best : i;
114+
int best = l + 1 < heapSize && heap[l + 1][1] < heap[l][1] ? l + 1 : l;
115+
best = heap[best][1] < heap[i][1] ? best : i;
89116
if (best == i) {
90117
break;
91118
}
92119
swap(best, i);
93120
i = best;
94121
l = i * 2 + 1;
95122
}
96-
return e;
97123
}
98124

99125
public static boolean isEmpty() {
100126
return heapSize == 0;
101127
}
102128

129+
// 堆上,i位置的信息 和 j位置的信息 交换!
103130
public static void swap(int i, int j) {
104-
int tmp = heap[i];
131+
int a = heap[i][0];
132+
int b = heap[j][0];
133+
where[a] = j;
134+
where[b] = i;
135+
int[] tmp = heap[i];
105136
heap[i] = heap[j];
106137
heap[j] = tmp;
107138
}
@@ -116,9 +147,12 @@ public static void main(String[] args) throws IOException {
116147
m = (int) in.nval;
117148
build();
118149
for (int i = 0, u, v, w; i < m; i++) {
119-
in.nextToken(); u = (int) in.nval;
120-
in.nextToken(); v = (int) in.nval;
121-
in.nextToken(); w = (int) in.nval;
150+
in.nextToken();
151+
u = (int) in.nval;
152+
in.nextToken();
153+
v = (int) in.nval;
154+
in.nextToken();
155+
w = (int) in.nval;
122156
addEdge(u, v, w);
123157
addEdge(v, u, w);
124158
}
@@ -131,23 +165,18 @@ public static void main(String[] args) throws IOException {
131165
}
132166

133167
public static int prim() {
134-
set[1] = true;
168+
// 1节点出发
135169
nodeCnt = 1;
170+
where[1] = -2;
136171
for (int ei = head[1]; ei > 0; ei = next[ei]) {
137-
push(ei);
172+
addOrUpdateOrIgnore(ei);
138173
}
139174
int ans = 0;
140175
while (!isEmpty()) {
141-
int edge = pop();
142-
int u = to[edge];
143-
int w = weight[edge];
144-
if (!set[u]) {
145-
set[u] = true;
146-
nodeCnt++;
147-
ans += w;
148-
for (int ei = head[u]; ei > 0; ei = next[ei]) {
149-
push(ei);
150-
}
176+
pop();
177+
ans += w;
178+
for (int ei = head[u]; ei > 0; ei = next[ei]) {
179+
addOrUpdateOrIgnore(ei);
151180
}
152181
}
153182
return ans;

src/class061/Code03_OptimizeWaterDistribution.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public class Code03_OptimizeWaterDistribution {
1616
public static int minCostToSupplyWater(int n, int[] wells, int[][] pipes) {
1717
build(n);
1818
for (int i = 0; i < n; i++, cnt++) {
19+
// wells : 100 30
20+
// 0(1) 1(2)
1921
edges[cnt][0] = 0;
2022
edges[cnt][1] = i + 1;
2123
edges[cnt][2] = wells[i];

src/class061/Code04_CheckingExistenceOfEdgeLengthLimit.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public static boolean[] distanceLimitedPathsExist(int n, int[][] edges, int[][]
2828
build(n);
2929
boolean[] ans = new boolean[k];
3030
for (int i = 0, j = 0; i < k; i++) {
31+
// i : 问题编号
32+
// j : 边的编号
3133
for (; j < m && edges[j][2] < questions[i][2]; j++) {
3234
union(edges[j][0], edges[j][1]);
3335
}

0 commit comments

Comments
 (0)