Bài tập  /  Bài đang cần trả lời

Viết thuật toán Kruskal tìm đường đi ngắn nhất bằng ngôn ngữ C++ hoặc Python

Viết thuật toán Kruskal tìm đường đi ngắn nhất bằng ngôn ngữ C++ hoặc Python
2 trả lời
Hỏi chi tiết
88
Tham khảo câu trả lời từ Trợ lý ảo Lazi
Thuật toán Kruskal thực chất không tìm đường đi ngắn nhất, mà nó tìm cây bao trùm tối thiểu (MST) cho một đồ thị không hướng có trọng số cạnh. Tuy nhiên, nếu bạn đang tìm cách áp dụng một thuật toán tương tự cho tìm đường đi ngắn nhất, có lẽ bạn đang nghĩ đến thuật toán Dijkstra.

Dưới đây là phần triển khai thuật toán Kruskal sử dụng Python để tìm cây bao trùm tối thiểu trong một đồ thị:

```python
class UnionFind:
def __init__(self, n):
self.parent = list(range(n))
self.rank = [1] * n

def find(self, u):
if self.parent[u] != u:
self.parent[u] = self.find(self.parent[u])
return self.parent[u]

def union(self, u, v):
root_u = self.find(u)
root_v = self.find(v)
if root_u != root_v:
if self.rank[root_u] > self.rank[root_v]:
self.parent[root_v] = root_u
elif self.rank[root_u] < self.rank[root_v]:
self.parent[root_u] = root_v
else:
self.parent[root_v] = root_u
self.rank[root_u] += 1

def kruskal(n, edges):
edges.sort(key=lambda x: x[2]) # Sắp xếp theo trọng số cạnh
uf = UnionFind(n)
mst = []
total_weight = 0

for u, v, weight in edges:
if uf.find(u) != uf.find(v): # Nếu u và v không thuộc cùng một thành phần liên thông
uf.union(u, v)
mst.append((u, v, weight))
total_weight += weight

return mst, total_weight

# Ví dụ sử dụng:
n = 4 # Số đỉnh
edges = [
(0, 1, 10),
(0, 2, 6),
(0, 3, 5),
(1, 3, 15),
(2, 3, 4)
]

mst, total_weight = kruskal(n, edges)
print("Cây bao trùm tối thiểu:", mst)
print("Trọng số tổng:", total_weight)
```

### Giải thích:
- **UnionFind**: Đây là một cấu trúc dữ liệu để quản lý các thành phần liên thông trong đồ thị.
- **kruskal(n, edges)**: Hàm này nhận vào số đỉnh `n` và danh sách `edges`, mỗi cạnh được biểu diễn dưới dạng một tuple `(u, v, weight)`. Nó sẽ trả về cây bao trùm tối thiểu và tổng trọng số của nó.

### Tham khảo:
- Bạn có thể thử nghiệm mã nguồn trên bất kỳ công cụ Python nào.
- Điều chỉnh danh sách cạnh để kiểm tra với các đồ thị khác nhau.

Nếu bạn cần thuật toán Dijkstra để tìm đường đi ngắn nhất, hãy cho tôi biết!
1
1
quangcuongg
14/08 08:05:47
+5đ tặng
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <math.h>
#include <dos.h>
#define MAX 50
#define TRUE 1
#define FALSE 0
int n, m, minl, connect;
int dau[500],cuoi[500], w[500];
int daut[50], cuoit[50], father[50];
void Init(void){
int i; FILE *fp;
fp=fopen("baotrum1.in","r");
fscanf(fp, "%d%d", &n,&m);
printf("\n So dinh do thi:%d", n);
printf("\n So canh do thi:%d", m);
printf("\n Danh sach ke do thi:");
for(i=1; i<=m;i++){
fscanf(fp, "%d%d%d", &dau[i], &cuoi[i], &w[i]);
printf("\n Canh %d: ]]]", i, dau[i], cuoi[i], w[i]);
}
fclose(fp);getch();
}
void Heap(int First, int Last){
int j, k, t1, t2, t3;
j=First;
while(j<=(Last/2)){
if( (2*j)<Last && w[2*j + 1]<w[2*j])
k = 2*j +1;
else
k=2*j;if(w[k]<w[j]){
t1=dau[j]; t2=cuoi[j]; t3=w[j];
dau[j]=dau[k]; cuoi[j]=cuoi[k]; w[j]=w[k];
dau[k]=t1; cuoi[k]=t2; w[k]=t3;
j=k;
}
else j=Last;
}
}
int Find(int i){
int tro=i;
while(father[tro]>0)
tro=father[tro];
return(tro);
}
void Union(int i, int j){
int x = father[i]+father[j];
if(father[i]>father[j]) {
father[i]=j;
father[j]=x;
}
else {
father[j]=i;
father[i]=x;
}
}
void Krusal(void){
int i, last, u, v, r1, r2, ncanh, ndinh;
for(i=1; i<=n; i++)
father[i]=-1;
for(i= m/2;i>0; i++)
Heap(i,m); last=m; ncanh=0; ndinh=0;minl=0;c />while(ndinh<n-1 && ncanh<m){
ncanh=ncanh+1;
u=dau[1]; v=cuoi[1];
r1= Find(u); r2= Find(v);
if(r1!=r2) {
ndinh=ndinh+1; Union(r1,r2);
daut[ndinh]=u; cuoit[ndinh]=v;
minl=minl+w[1];
}
dau[1]=dau[last];
cuoi[1]=cuoi[last];
w[1]=w[last];
last=last-1;
Heap(1, last);
}
if(ndinh!=n-1) c />}
void Result(void){
int i;
printf("\n Do dai cay khung nho nhat:%d", minl);
printf("\n Cac canh cua cay khung nho nhat:");
for(i=1; i<n; i++)
printf("\n ]]",daut[i], cuoit[i]);
printf("\n");
}
void main(void){
clrscr(); Init();
Krusal();Result(); getch();
}

Mở khóa để xem toàn bộ nội dung trả lời

(?)
Bạn đã đạt đến giới hạn của mình. Bằng cách Đăng ký tài khoản, bạn có thể xem toàn bộ nội dung trả lời
Cải thiện điểm số của bạn bằng cách đăng ký tài khoản Lazi.
Xem toàn bộ các câu trả lời, chat trực tiếp 1:1 với đội ngũ Gia sư Lazi bằng cách Đăng ký tài khoản ngay bây giờ
Tôi đã có tài khoản? Đăng nhập
0
0
Tuấn Phạm
21/08 20:14:40
MÃ PYTHON:
  1. class Edge:
  2.     def __init__(self, u, v, weight):
  3.         self.u = u
  4.         self.v = v
  5.         self.weight = weight
  6.  
  7. def __lt__(self, other):
  8.     return self.weight < other.weight
  9.  
  10. class Graph:
  11.    def __init__(self, vertices):
  12.         self.V = vertices
  13.         self.edges = []
  14.  
  15. def add_edge(self, u, v, weight):
  16.     self.edges.append(Edge(u, v, weight))
  17.  
  18.  
  19. def find(self, parent, i):
  20.     if parent[i] == i:
  21.         return i
  22.     else:
  23.         return self.find(parent, parent[i])
  24.  
  25. def union(self, parent, rank, x, y):
  26.     xroot = self.find(parent, x)
  27.     yroot = self.find(parent, y)
  28.  
  29.     if rank[xroot] < rank[yroot]:
  30.         parent[xroot] = yroot
  31.     elif rank[xroot] > rank[yroot]:
  32.         parent[yroot] = xroot
  33.     else:
  34.         parent[yroot] = xroot rank[xroot] += 1
  35.  
  36.  
  37. def kruskal(self):
  38.     result = []
  39.     i = 0
  40.     e = 0 
  41.     self.edges = sorted(self.edges)
  42.    
  43.     parent = []
  44.     rank = []
  45.     for node in range(self.V):
  46.         parent.append(node)
  47.         rank.append(0)
  48.     while e < self.V - 1:
  49.         u, v, weight = self.edges[i].u, self.edges[i].v, self.edges[i].weight
  50.         i = i + 1
  51.         x = self.find(parent, u)
  52.         y = self.find(parent, v)
  53.  
  54.         if x != y:
  55.             e = e + 1
  56.             result.append([u, v, weight])
  57.             self.union(parent, rank, x, y)
  58.  
  59.     print("Cây khung nhỏ nhất bao gồm các cạnh:")
  60.     for u, v, weight in result:
  61.         print(f"Cạnh {u} -- {v} có trọng số {weight}")
  62.  
  63.  
  64. g = Graph(4)
  65. g.add_edge(0, 1, 10)
  66. g.add_edge(0, 2, 6)
  67. g.add_edge(0, 3, 5)
  68. g.add_edge(1, 3, 15)
  69. g.add_edge(2, 3, 4)
  70.  
  71. g.kruskal()

GIẢI THÍCH:
  1. Lớp Edge: Đại diện cho một cạnh với hai đỉnh u, v và trọng số weight.
  2. Lớp Graph: Đại diện cho đồ thị với số đỉnh V và danh sách các cạnh edges.
    • Hàm add_edge: Thêm một cạnh vào đồ thị.
    • Hàm find: Tìm tập hợp đại diện của một đỉnh.
    • Hàm union: Hợp nhất hai tập hợp (tập hợp chứa hai đỉnh của một cạnh).
    • Hàm kruskal: Thực hiện thuật toán Kruskal.
  3. Thuật toán chính:
    • Các cạnh được sắp xếp theo thứ tự tăng dần của trọng số.
    • Các cạnh được chọn sao cho không tạo ra chu trình, đến khi cây khung có đủ V-1 cạnh.

Bạn hỏi - Lazi trả lời

Bạn muốn biết điều gì?

GỬI CÂU HỎI
Học tập không giới hạn cùng học sinh cả nước và AI, sôi động, tích cực, trải nghiệm
Bài tập liên quan
Bài tập Lập trình Đại học mới nhất

Hôm nay bạn thế nào? Hãy nhấp vào một lựa chọn, nếu may mắn bạn sẽ được tặng 50.000 xu từ Lazi

Vui Buồn Bình thường

Học ngoại ngữ với Flashcard

×
Gia sư Lazi Gia sư
×
Trợ lý ảo Trợ lý ảo