Skip to content

Commit 39369af

Browse files
committed
Improve Kruskals materials
1 parent 1cb32d1 commit 39369af

File tree

8 files changed

+139
-27
lines changed

8 files changed

+139
-27
lines changed

Seminars/sem_14/README.md

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,59 @@ prim(5, 5, graph) # 13
7575
![Prim's algorithm creating a MST of a graph, step by step example.](media/prims_algorithm_example.png)
7676

7777
## Алгоритъм на Крускал (Kruskal's algorithm)
78-
![Alt text](media/mst_vs_dijkstra.png)
78+
7979
- Намира минимално покриващо дърво на граф.
8080
- Сортира ребрата по минимална тежест, като на всяка стъпка добавя реброто с най-малка тежест, което няма да създаде цикъл в графа.
81+
- Използва структурата *Disjoint set* за оптимална проверка за цикличност.
8182
- Сложност по време *O(E\*logE)* заради сортирането на всички ребра.
8283
- При *dense* граф, когато *Е = V<sup>2</sup>*, *O(ElogE) = O(ElogV<sup>2</sup>) = O(2ElogV) = O(ElogV)*
83-
-
84+
85+
Подробно описание как работи Disjoint-set (Union-find) структурата в [playground-а](playground_14.ipynb).
86+
87+
```python
88+
def find(x, parents):
89+
if parents[x] == x:
90+
return x
91+
92+
furthest_parent = find(parents[x], parents)
93+
parents[x] = furthest_parent
94+
95+
return furthest_parent
96+
97+
def union(x, y, parents, rank):
98+
x_root = find(x, parents)
99+
y_root = find(y, parents)
100+
101+
if rank[x_root] < rank[y_root]:
102+
parents[x_root] = y_root
103+
elif rank[x_root] > rank[y_root]:
104+
parents[y_root] = x_root
105+
else:
106+
parents[x_root] = y_root
107+
rank[y_root] += 1
108+
109+
def kruskal(V, edges):
110+
edges.sort(key=lambda x: x[2])
111+
parents = [i for i in range(V + 1)]
112+
rank = [0] * (V + 1)
113+
mst_weight = 0
114+
115+
for x, y, w in edges:
116+
if find(x, parents) != find(y, parents):
117+
mst_weight += w
118+
union(x, y, parents, rank)
119+
120+
return mst_weight
121+
122+
kruskal(5 , graph_list_of_edges) # 13
123+
```
84124

85125
![Kruskal's algorithm creating a MST of a graph, step by step example.](media/kruskals_algorithm_example.png)
86126

87127

88128
## Задачи за упражнение
89129

90130
- [Prim's (MST) : Special Subtree](https://www.hackerrank.com/challenges/primsmstsub/problem)
131+
- [Kruskal (MST): Really Special Subtree](https://www.hackerrank.com/challenges/kruskalmstrsub/problem)
91132

92133
Решения на задачите: [тук](/Tasks/tasks_14)

Seminars/sem_14/playground_14.ipynb

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
},
3131
{
3232
"cell_type": "code",
33-
"execution_count": 479,
33+
"execution_count": 20,
3434
"metadata": {},
3535
"outputs": [],
3636
"source": [
@@ -59,7 +59,7 @@
5959
},
6060
{
6161
"cell_type": "code",
62-
"execution_count": 480,
62+
"execution_count": 21,
6363
"metadata": {},
6464
"outputs": [
6565
{
@@ -117,7 +117,7 @@
117117
},
118118
{
119119
"cell_type": "code",
120-
"execution_count": 481,
120+
"execution_count": 22,
121121
"metadata": {},
122122
"outputs": [
123123
{
@@ -184,7 +184,7 @@
184184
},
185185
{
186186
"cell_type": "code",
187-
"execution_count": 482,
187+
"execution_count": 23,
188188
"metadata": {},
189189
"outputs": [
190190
{
@@ -235,7 +235,7 @@
235235
},
236236
{
237237
"cell_type": "code",
238-
"execution_count": 483,
238+
"execution_count": 24,
239239
"metadata": {},
240240
"outputs": [
241241
{
@@ -276,7 +276,7 @@
276276
},
277277
{
278278
"cell_type": "code",
279-
"execution_count": 484,
279+
"execution_count": 25,
280280
"metadata": {},
281281
"outputs": [
282282
{
@@ -310,7 +310,7 @@
310310
},
311311
{
312312
"cell_type": "code",
313-
"execution_count": 485,
313+
"execution_count": 26,
314314
"metadata": {},
315315
"outputs": [
316316
{
@@ -341,7 +341,7 @@
341341
},
342342
{
343343
"cell_type": "code",
344-
"execution_count": 486,
344+
"execution_count": 27,
345345
"metadata": {},
346346
"outputs": [
347347
{
@@ -366,7 +366,7 @@
366366
},
367367
{
368368
"cell_type": "code",
369-
"execution_count": 487,
369+
"execution_count": 28,
370370
"metadata": {},
371371
"outputs": [
372372
{
@@ -423,7 +423,7 @@
423423
},
424424
{
425425
"cell_type": "code",
426-
"execution_count": 488,
426+
"execution_count": 29,
427427
"metadata": {},
428428
"outputs": [
429429
{
@@ -463,7 +463,7 @@
463463
},
464464
{
465465
"cell_type": "code",
466-
"execution_count": 489,
466+
"execution_count": 30,
467467
"metadata": {},
468468
"outputs": [
469469
{
@@ -497,7 +497,7 @@
497497
},
498498
{
499499
"cell_type": "code",
500-
"execution_count": 490,
500+
"execution_count": 31,
501501
"metadata": {},
502502
"outputs": [
503503
{
@@ -561,7 +561,7 @@
561561
},
562562
{
563563
"cell_type": "code",
564-
"execution_count": 491,
564+
"execution_count": 32,
565565
"metadata": {},
566566
"outputs": [],
567567
"source": [
@@ -599,7 +599,7 @@
599599
},
600600
{
601601
"cell_type": "code",
602-
"execution_count": 492,
602+
"execution_count": 33,
603603
"metadata": {},
604604
"outputs": [
605605
{
@@ -635,7 +635,7 @@
635635
},
636636
{
637637
"cell_type": "code",
638-
"execution_count": 493,
638+
"execution_count": 34,
639639
"metadata": {},
640640
"outputs": [
641641
{
@@ -667,7 +667,7 @@
667667
},
668668
{
669669
"cell_type": "code",
670-
"execution_count": 494,
670+
"execution_count": 35,
671671
"metadata": {},
672672
"outputs": [
673673
{
@@ -747,7 +747,7 @@
747747
},
748748
{
749749
"cell_type": "code",
750-
"execution_count": 495,
750+
"execution_count": 36,
751751
"metadata": {},
752752
"outputs": [],
753753
"source": [
@@ -776,7 +776,7 @@
776776
},
777777
{
778778
"cell_type": "code",
779-
"execution_count": 496,
779+
"execution_count": 37,
780780
"metadata": {},
781781
"outputs": [
782782
{
@@ -785,7 +785,7 @@
785785
"13"
786786
]
787787
},
788-
"execution_count": 496,
788+
"execution_count": 37,
789789
"metadata": {},
790790
"output_type": "execute_result"
791791
}
@@ -813,7 +813,7 @@
813813
" rank[y_root] += 1\n",
814814
"\n",
815815
"def kruskal(V, edges):\n",
816-
" edges.sort(key=lambda x: x[2]) # Sort edges by weight\n",
816+
" edges.sort(key=lambda x: x[2]) # Sorts edges by weight\n",
817817
" parents = [i for i in range(V + 1)]\n",
818818
" rank = [0] * (V + 1)\n",
819819
" mst_weight = 0\n",
@@ -845,7 +845,7 @@
845845
},
846846
{
847847
"cell_type": "code",
848-
"execution_count": 497,
848+
"execution_count": 38,
849849
"metadata": {},
850850
"outputs": [
851851
{
@@ -880,7 +880,7 @@
880880
"13"
881881
]
882882
},
883-
"execution_count": 497,
883+
"execution_count": 38,
884884
"metadata": {},
885885
"output_type": "execute_result"
886886
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
def find(x, parents):
2+
if parents[x] == x:
3+
return x
4+
5+
furthest_parent = find(parents[x], parents)
6+
parents[x] = furthest_parent
7+
8+
return furthest_parent
9+
10+
def union(x, y, parents, rank):
11+
x_root = find(x, parents)
12+
y_root = find(y, parents)
13+
14+
if rank[x_root] < rank[y_root]:
15+
parents[x_root] = y_root
16+
elif rank[x_root] > rank[y_root]:
17+
parents[y_root] = x_root
18+
else:
19+
parents[x_root] = y_root
20+
rank[y_root] += 1
21+
22+
def kruskal(V, edges):
23+
edges.sort(key=lambda x: x[2])
24+
parents = [i for i in range(V + 1)]
25+
rank = [0] * (V + 1)
26+
mst_weight = 0
27+
28+
for x, y, w in edges:
29+
if find(x, parents) != find(y, parents):
30+
mst_weight += w
31+
union(x, y, parents, rank)
32+
33+
return mst_weight
34+
35+
36+
V, E = map(int, input().split())
37+
edges = [tuple(map(int, input().split())) for i in range(E)]
38+
39+
result = kruskal(V, edges)
40+
print(result)

Tasks/tasks_14/prims_special_subtree/solution_kruskal_better.py renamed to Tasks/tasks_14/kruskals_really_special_subtree/solution_kruskal_better.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,5 @@ def kruskal(V, edges):
3232
N, M = map(int, input().split())
3333
edges = [tuple(map(int, input().split())) for _ in range(M)]
3434

35-
start = int(input())
3635
mst_weight = kruskal(N, edges)
3736
print(mst_weight)

Tasks/tasks_14/prims_special_subtree/solution_kruskal_medium.py renamed to Tasks/tasks_14/kruskals_really_special_subtree/solution_kruskal_medium.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,5 @@ def kruskal(V, edges):
3131
N, M = map(int, input().split())
3232
edges = [tuple(map(int, input().split())) for _ in range(M)]
3333

34-
start = int(input())
3534
mst_weight = kruskal(N, edges)
3635
print(mst_weight)

Tasks/tasks_14/prims_special_subtree/solution_kruskal_worst.py renamed to Tasks/tasks_14/kruskals_really_special_subtree/solution_kruskal_worst.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,5 @@ def kruskal(V, edges):
2828
N, M = map(int, input().split())
2929
edges = [tuple(map(int, input().split())) for _ in range(M)]
3030

31-
start = int(input())
3231
mst_weight = kruskal(N, edges)
3332
print(mst_weight)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from heapq import heappush, heappop
2+
3+
def prim(start, V, graph):
4+
visited = set()
5+
pq = [(0, start)]
6+
mst_weight = 0
7+
8+
while len(visited) != V:
9+
current_weight, current = heappop(pq)
10+
11+
if current in visited:
12+
continue
13+
14+
visited.add(current)
15+
mst_weight += current_weight
16+
17+
for neighb, weight in graph[current]:
18+
if neighb in visited:
19+
continue
20+
21+
heappush(pq, (weight, neighb))
22+
23+
return mst_weight
24+
25+
N, M = map(int, input().split())
26+
graph = {v: set() for v in range(1, N + 1)}
27+
28+
for _ in range(M):
29+
x, y, w = map(int, input().split())
30+
graph[x].add((y, w))
31+
graph[y].add((x, w))
32+
33+
mst_weight = prim(1, N, graph)
34+
print(mst_weight)
File renamed without changes.

0 commit comments

Comments
 (0)