Menu
×

Được chứng nhận

Ghi lại kiến ​​thức của bạn

Đăng nhập Đăng ký

Tạo Tài khoản Example.com.vn miễn phí để cải thiện trải nghiệm học tập của bạn

Người tìm đường và việc học của tôi

Theo dõi tiến độ học tập của bạn tại Example.com.vn và thu thập phần thưởng

Nâng cấp

Trở thành người dùng PLUS và mở khóa các tính năng mạnh mẽ (không có quảng cáo, lưu trữ, hỗ trợ, ..)

Bắt đầu từ đâu

Bạn không chắc chắn muốn bắt đầu từ đâu? Đi theo con đường được hướng dẫn của chúng tôi

Trình chỉnh sửa mã (Dùng thử)

Với trình chỉnh sửa mã trực tuyến của chúng tôi, bạn có thể chỉnh sửa mã và xem kết quả trong trình duyệt của mình

Video

Tìm hiểu những điều cơ bản về HTML qua video hướng dẫn thú vị và hấp dẫn

Mẫu

Chúng tôi đã tạo một loạt mẫu trang web đáp ứng mà bạn có thể sử dụng - miễn phí!

Web hosting

Lưu trữ trang web của riêng bạn và chia sẻ nó với mọi người với Example.com.vn Spaces

Tạo một máy chủ

Tạo máy chủ của riêng bạn bằng Python, PHP, React.js, Node.js, Java, C#, v.v.

Làm thế nào để

Bộ sưu tập lớn các đoạn mã cho HTML, CSS và JavaScript

Khung CSS

Xây dựng các trang web nhanh và phản hồi bằng cách sử dụng khung W3.CSS miễn phí của chúng tôi

Thống kê trình duyệt

Đọc xu hướng dài hạn của việc sử dụng trình duyệt

Tốc độ gõ

Kiểm tra tốc độ đánh máy của bạn

Đào tạo AWS

Tìm hiểu dịch vụ web của Amazon

Bộ chọn màu

Sử dụng công cụ chọn màu của chúng tôi để tìm các màu RGB, HEX và HSL khác nhau. Bánh xe màu hình tròn thể hiện sự chuyển màu của màu trong quang phổ

Trò chơi mã

Trò chơi mã hóa W3Schools! Giúp linh miêu thu thập nón thông Logo Lynx

Đặt mục tiêu

Nhận hành trình học tập được cá nhân hóa dựa trên các kỹ năng và mục tiêu hiện tại của bạn

Bản tin

Tham gia bản tin của chúng tôi và có quyền truy cập vào nội dung độc quyền mỗi tháng

Việc làm

Thuê những tài năng công nghệ hàng đầu. Hợp lý hóa quy trình tuyển dụng của bạn để có đội ngũ phù hợp hoàn hảo

Lớp học

Hãy liên hệ để sử dụng Example.com.vn Plus và các chứng chỉ với tư cách là một tổ chức giáo dục

×
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP CÁCH W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS R TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI GO KOTLIN SASS VUE DSA GEN AI SCIPY AWS AN NINH MẠNG DỮ LIỆU KHOA HỌC

Hướng dẫn DSA

DSA TRANG CHỦ DSA Giới thiệu Thuật toán đơn giản DSA

Mảng

Mảng DSA Sắp xếp bong bóng DSA Sắp xếp lựa chọn DSA Sắp xếp chèn DSA Sắp xếp nhanh DSA Sắp xếp đếm DSA Sắp xếp cơ số DSA Sắp xếp hợp nhất DSA Tìm kiếm tuyến tính DSA Tìm kiếm nhị phân DSA

Danh sách liên kết

Danh sách liên kết DSA Danh sách liên kết DSA trong bộ nhớ Danh sách liên kết DSA Các loại Danh sách liên kết Hoạt động

Ngăn xếp & hàng đợi

Ngăn xếp DSA Hàng đợi DSA

Bảng băm

Bảng băm DSA Bộ hàm băm DSA Bản đồ hàm băm DSA

Cây

Cây DSA Cây nhị phân DSA DSA Traversal đặt hàng trước DSA Traversal theo thứ tự DSA Traversal DSA sau thực hiện mảng DSA Cây tìm kiếm nhị phân DSA Cây AVL DSA

Đồ thị

Đồ thị DSA Thực hiện đồ thị Đồ thị DSA Phát hiện chu trình DSA truyền tải

Con đường ngắn nhất

Đường đi ngắn nhất DSA DSA Bellman-Ford của DSA Dijkstra

Cây bao trùm tối thiểu

Cây khung tối thiểu DSA Prim's DSA Kruskal's

Lưu lượng cực đại

DSA Lưu lượng tối đa DSA Ford-Fulkerson DSA Edmonds-Karp

Độ phức tạp thời gian

Giới thiệu Sắp xếp bong bóng Lựa chọn Sắp xếp Chèn Sắp xếp Sắp xếp nhanh Đếm Sắp xếp Cơ số Sắp xếp Hợp nhất Sắp xếp Tìm kiếm tuyến tính Tìm kiếm nhị phân

Tham chiếu DSA

Thuật toán Euclide DSA Thuật toán tham lam DSA Ghi nhớ DSA DSA Người bán hàng du lịch

Ví dụ về DSA

Ví dụ về DSA Bài tập DSA Câu hỏi DSA Chứng chỉ DSA

Thuật toán DSA Prim

Thuật toán Prim được phát minh vào năm 1930 bởi nhà toán học người Séc Vojtěch Jarník.

Thuật toán này sau đó được Robert C. Prim khám phá lại vào năm 1957 và cũng được Edsger W. Dijkstra khám phá lại vào năm 1959. Do đó, thuật toán này đôi khi còn được gọi là "thuật toán Jarník" hay "thuật toán Prim-Jarník".

Thuật toán Prim

Thuật toán của Prim tìm Cây bao trùm tối thiểu (MST) trong đồ thị liên thông và vô hướng.


{{ msgDone }}

MST được thuật toán Prim tìm thấy là tập hợp các cạnh trong biểu đồ, kết nối tất cả các đỉnh với tổng trọng số cạnh tối thiểu.

Thuật toán của Prim tìm MST bằng cách trước tiên thêm một đỉnh ngẫu nhiên vào MST. Sau đó, thuật toán sẽ tìm đỉnh có trọng số cạnh thấp nhất so với MST hiện tại và đưa đỉnh đó vào MST. Thuật toán của Prim tiếp tục thực hiện việc này cho đến khi tất cả các nút được đưa vào MST.

Thuật toán của Prim rất tham lam và có cách đơn giản để tạo cây bao trùm tối thiểu.

Để thuật toán của Prim hoạt động, tất cả các nút phải được kết nối. Để tìm MST trong đồ thị không liên thông, có thể sử dụng thuật toán Kruskal . Bạn có thể đọc về thuật toán Kruskal ở trang tiếp theo.

Làm thế nào nó hoạt động:

  1. Chọn một đỉnh ngẫu nhiên làm điểm bắt đầu và đưa nó làm đỉnh đầu tiên trong MST.
  2. So sánh các cạnh đi ra từ MST. Chọn cạnh có trọng số thấp nhất nối một đỉnh trong số các đỉnh MST với một đỉnh bên ngoài MST.
  3. Thêm cạnh và đỉnh đó vào MST.
  4. Tiếp tục thực hiện bước 2 và 3 cho đến khi tất cả các đỉnh thuộc MST.

LƯU Ý: Vì đỉnh bắt đầu được chọn ngẫu nhiên nên có thể có các cạnh khác nhau được đưa vào MST cho cùng một đồ thị, nhưng tổng trọng số cạnh của MST sẽ vẫn có cùng giá trị tối thiểu.


Chạy qua thủ công

Chúng ta hãy xem thuật toán của Prim theo cách thủ công trên biểu đồ bên dưới để chúng ta hiểu các thao tác chi tiết từng bước trước khi thử lập trình nó.

Thuật toán của Prim bắt đầu phát triển Cây bao trùm tối thiểu (MST) từ một đỉnh ngẫu nhiên, nhưng đối với đỉnh trình diễn này, đỉnh A được chọn làm đỉnh bắt đầu.

{{ edge.weight }} {{el.name}}

Từ đỉnh A, MST phát triển dọc theo cạnh có trọng số thấp nhất. Vậy đỉnh A và D bây giờ thuộc nhóm đỉnh thuộc Cây bao trùm tối thiểu.

{{ edge.weight }} {{el.name}}

Mảng parents là trọng tâm trong cách thuật toán của Prim phát triển các cạnh trong MST.

Tại thời điểm này, mảng parents trông như thế này:

 parents = [-1,  0, -1,  0,  3,  3, -1, -1]
#vertices [ A,  B,  C,  D,  E,  F,  G,  H]

Đỉnh A, đỉnh bắt đầu, không có đỉnh cha và do đó có giá trị -1 . Cha của Vertex D là A, đó là lý do tại sao giá trị cha của D là 0 (đỉnh A nằm ở chỉ số 0). Cha mẹ của B cũng là A, và D là cha mẹ của E và F.

Mảng parents giúp chúng ta giữ nguyên cấu trúc cây MST (một đỉnh chỉ có thể có một cha mẹ).

Ngoài ra, để tránh chu kỳ và theo dõi các đỉnh hiện có trong MST, mảng in_mst được sử dụng.

Mảng in_mst hiện tại trông như thế này:

 in_mst = [ true, false, false,  true, false, false, false, false]
#vertices [    A,     B,     C,     D,     E,     F,     G,     H]

Bước tiếp theo trong thuật toán của Prim là đưa thêm một đỉnh nữa vào làm một phần của MST và đỉnh gần nhất với các nút MST A và D hiện tại sẽ được chọn.

Vì cả AB và DF đều có cùng trọng số cạnh thấp nhất 4 nên B hoặc F có thể được chọn làm đỉnh MST tiếp theo. Chúng tôi chọn B làm đỉnh MST tiếp theo cho phần trình diễn này.

{{ edge.weight }} {{el.name}}

Như bạn thấy, cạnh MST tới E trước đây xuất phát từ đỉnh D, bây giờ nó xuất phát từ đỉnh B, vì BE có trọng số 6 thấp hơn DE có trọng số 7 . Vertex E chỉ có thể có một cha trong cấu trúc cây MST (và trong mảng parents ), do đó BE và DE không thể cùng là các cạnh MST của E.

Đỉnh tiếp theo trong MST là đỉnh C, vì cạnh BC có trọng số 3 là cạnh có trọng số ngắn nhất tính từ đỉnh MST hiện tại.

{{ edge.weight }} {{el.name}}

Vì đỉnh C được bao gồm trong MST, các cạnh ra khỏi C được kiểm tra để xem liệu có cạnh nào có trọng số thấp hơn từ đỉnh MST này đến các đỉnh bên ngoài MST hay không. Cạnh CE có trọng số ( 3 ) thấp hơn cạnh BE MST trước đó ( 6 ) và cạnh CH được đưa vào MST với trọng số cạnh 2 .

Đỉnh H là đỉnh tiếp theo được đưa vào MST, vì nó có trọng số cạnh thấp nhất 6 và đỉnh H trở thành đỉnh cha của đỉnh G trong mảng parents .

{{ edge.weight }} {{el.name}}

Đỉnh tiếp theo được đưa vào MST là E hoặc F vì chúng có trọng số cạnh thấp nhất: 4 .

Chúng tôi chọn đỉnh E làm đỉnh tiếp theo được đưa vào MST cho phần trình diễn này.

{{ edge.weight }} {{el.name}}

Hai đỉnh tiếp theo và cuối cùng được thêm vào MST là các đỉnh F và G. DF là cạnh MST đến F và EG là cạnh MST đến G vì các cạnh này là các cạnh có trọng số thấp nhất so với MST hiện tại.

Chạy mô phỏng bên dưới để xem thuật toán của Prim thực hiện các bước thủ công mà chúng ta vừa thực hiện.

{{ edge.weight }} {{el.name}}
{{ msgDone }}

Triển khai thuật toán Prim

Để thuật toán của Prim tìm Cây bao trùm tối thiểu (MST), chúng tôi tạo một lớp Graph . Sau này chúng ta sẽ sử dụng các phương thức bên trong lớp Graph này để tạo biểu đồ từ ví dụ trên và chạy thuật toán của Prim trên đó.

 class Graph:
    def __init__(self, size):
        self.adj_matrix = [[0] * size for _ in range(size)]
        self.size = size
        self.vertex_data = [''] * size

    def add_edge(self, u, v, weight):
        if 0 <= u < self.size and 0 <= v < self.size:
            self.adj_matrix[u][v] = weight
            self.adj_matrix[v][u] = weight  # For undirected graph

    def add_vertex_data(self, vertex, data):
        if 0 <= vertex < self.size:
            self.vertex_data[vertex] = data

Dòng 3-5: Lúc đầu, ma trận kề trống, nghĩa là không có cạnh nào trong đồ thị. Ngoài ra, các đỉnh không có tên để bắt đầu.

Dòng 7-10: Phương thức add_edge dùng để thêm một cạnh, với giá trị trọng số của cạnh, vào đồ thị vô hướng.

Dòng 12-14: Phương thức add_vertex_data được sử dụng để đặt tên cho các đỉnh, ví dụ như 'A' hoặc 'B'.

Bây giờ cấu trúc để tạo biểu đồ đã sẵn sàng, chúng ta có thể triển khai thuật toán Prim như một phương thức bên trong lớp Graph :

    def prims_algorithm(self):
        in_mst = [False] * self.size
        key_values = [float('inf')] * self.size
        parents = [-1] * self.size

        key_values[0] = 0  # Starting vertex

        print("Edge \tWeight")
        for _ in range(self.size):
            u = min((v for v in range(self.size) if not in_mst[v]), key=lambda v: key_values[v])

            in_mst[u] = True

            if parents[u] != -1:  # Skip printing for the first vertex since it has no parent
                print(f"{self.vertex_data[parents[u]]}-{self.vertex_data[u]} \t{self.adj_matrix[u][parents[u]]}")

            for v in range(self.size):
                if 0 < self.adj_matrix[u][v] < key_values[v] and not in_mst[v]:
                    key_values[v] = self.adj_matrix[u][v]
                    parents[v] = u

Dòng 17: Mảng in_mst chứa trạng thái của các đỉnh hiện có trong MST. Ban đầu, không có đỉnh nào là một phần của MST.

Dòng 18: Mảng key_values ​​giữ khoảng cách ngắn nhất hiện tại từ các đỉnh MST đến mỗi đỉnh bên ngoài MST.

Dòng 19: Các cạnh MST được lưu trữ trong mảng parents . Mỗi cạnh MST được lưu trữ bằng cách lưu trữ chỉ mục gốc cho mỗi đỉnh.

Dòng 21: Để đơn giản và làm cho mã này chạy giống như trong hoạt hình/ví dụ "Chạy qua thủ công" ở trên, đỉnh đầu tiên (đỉnh A ở chỉ số 0 ) được đặt làm đỉnh nhìn chằm chằm. Việc thay đổi chỉ mục thành 4 sẽ chạy thuật toán Prim từ đỉnh E và thuật toán đó cũng hoạt động tốt.

Dòng 25: Chỉ mục được tìm thấy cho đỉnh có giá trị khóa thấp nhất chưa thuộc MST. Hãy xem những giải thích này cho minlambda để hiểu rõ hơn về dòng mã Python này.

Dòng 32-35: Sau khi một đỉnh mới được thêm vào MST (dòng 27), phần mã này sẽ kiểm tra xem liệu bây giờ có các cạnh từ đỉnh MST mới được thêm này có thể hạ giá trị khóa xuống các đỉnh khác bên ngoài MST hay không . Nếu đúng như vậy, mảng key_values ​​và mảng parents sẽ được cập nhật tương ứng. Có thể thấy rõ điều này trong hoạt ảnh khi một đỉnh mới được thêm vào MST và trở thành đỉnh hoạt động (hiện tại).

Bây giờ, hãy tạo biểu đồ từ "Chạy qua thủ công" ở trên và chạy thuật toán của Prim trên đó:

Ví dụ

Trăn:

 class Graph:
    def __init__(self, size):
        self.adj_matrix = [[0] * size for _ in range(size)]
        self.size = size
        self.vertex_data = [''] * size

    def add_edge(self, u, v, weight):
        if 0 <= u < self.size and 0 <= v < self.size:
            self.adj_matrix[u][v] = weight
            self.adj_matrix[v][u] = weight  # For undirected graph

    def add_vertex_data(self, vertex, data):
        if 0 <= vertex < self.size:
            self.vertex_data[vertex] = data

    def prims_algorithm(self):
        in_mst = [False] * self.size
        key_values = [float('inf')] * self.size
        parents = [-1] * self.size

        key_values[0] = 0  # Starting vertex

        print("Edge \tWeight")
        for _ in range(self.size):
            u = min((v for v in range(self.size) if not in_mst[v]), key=lambda v: key_values[v])

            in_mst[u] = True

            if parents[u] != -1:  # Skip printing for the first vertex since it has no parent
                print(f"{self.vertex_data[parents[u]]}-{self.vertex_data[u]} \t{self.adj_matrix[u][parents[u]]}")

            for v in range(self.size):
                if 0 < self.adj_matrix[u][v] < key_values[v] and not in_mst[v]:
                    key_values[v] = self.adj_matrix[u][v]
                    parents[v] = u

g = Graph(8)

g.add_vertex_data(0, 'A')
g.add_vertex_data(1, 'B')
g.add_vertex_data(2, 'C')
g.add_vertex_data(3, 'D')
g.add_vertex_data(4, 'E')
g.add_vertex_data(5, 'F')
g.add_vertex_data(6, 'G')
g.add_vertex_data(7, 'H')

g.add_edge(0, 1, 4)  # A - B
g.add_edge(0, 3, 3)  # A - D
g.add_edge(1, 2, 3)  # B - C
g.add_edge(1, 3, 5)  # B - D
g.add_edge(1, 4, 6)  # B - E
g.add_edge(2, 4, 4)  # C - E
g.add_edge(2, 7, 2)  # C - H
g.add_edge(3, 4, 7)  # D - E
g.add_edge(3, 5, 4)  # D - F
g.add_edge(4, 5, 5)  # E - F
g.add_edge(4, 6, 3)  # E - G
g.add_edge(5, 6, 7)  # F - G
g.add_edge(6, 7, 5)  # G - H

print("Prim's Algorithm MST:")
g.prims_algorithm()
Chạy ví dụ »

Dòng 32: Chúng ta thực sự có thể tránh vòng lặp cuối cùng trong thuật toán của Prim bằng cách thay đổi dòng này thành for _ in range(self.size - 1): . Điều này là do khi chỉ có một đỉnh chưa có trong MST, thì đỉnh cha cho đỉnh đó đã được đặt chính xác trong mảng parents , do đó MST thực sự đã được tìm thấy tại thời điểm này.


Độ phức tạp thời gian của thuật toán Prim

Để có giải thích chung về độ phức tạp của thời gian, hãy truy cập trang này .

Với \(V\) là số đỉnh trong đồ thị của chúng ta, độ phức tạp về thời gian của thuật toán Prim là

\[ O( V^2 ) \]

Lý do tại sao chúng ta gặp sự phức tạp về thời gian này là do các vòng lặp lồng nhau bên trong thuật toán của Prim (một vòng lặp for với hai vòng lặp for khác bên trong nó).

Vòng lặp for đầu tiên (dòng 24) đi qua tất cả các đỉnh trong biểu đồ. Điều này có độ phức tạp về thời gian \(O(V)\).

Vòng lặp for thứ hai (dòng 25) đi qua tất cả các đỉnh liền kề trong biểu đồ để tìm đỉnh có giá trị khóa thấp nhất nằm ngoài MST, sao cho nó có thể là đỉnh tiếp theo được đưa vào MST. Điều này có độ phức tạp về thời gian \(O(V)\).

Sau khi một đỉnh mới được đưa vào MST, vòng lặp for thứ ba (dòng 32) sẽ kiểm tra tất cả các đỉnh khác để xem liệu có cạnh đi ra từ đỉnh MST mới được thêm vào đến các đỉnh bên ngoài MST có thể dẫn đến giá trị khóa thấp hơn và được cập nhật hay không quan hệ cha mẹ. Điều này cũng có độ phức tạp về thời gian \(O(V)\).

Kết hợp độ phức tạp của thời gian lại với nhau, chúng ta có:

\[ \begin{equation} \begin{aligned} O(V)\cdot (O(V)+O(V)) & = O(V)\cdot (2\cdot O(V)) \\ & = O(V\cdot 2\cdot V) \\ & = O(2\cdot V^2) \\\\ & = O(V^2) \end{aligned} \end{equation} \]

Bằng cách sử dụng cấu trúc dữ liệu hàng đợi ưu tiên để quản lý các giá trị khóa, thay vì sử dụng mảng như chúng tôi làm ở đây, độ phức tạp về thời gian của thuật toán Prim có thể giảm xuống:

\[ O( E \cdot \log{V}) \]

Trong đó \(E\) là số cạnh trong đồ thị và \(V\) là số đỉnh.

Việc triển khai thuật toán Prim như vậy bằng cách sử dụng hàng đợi ưu tiên là tốt nhất cho các đồ thị thưa thớt. Đồ thị thưa thớt khi mỗi đỉnh chỉ được kết nối với một vài đỉnh khác.



×

Liên hệ bán hàng

Nếu bạn muốn sử dụng dịch vụ của Example.com.vn với tư cách là một tổ chức giáo dục, nhóm hoặc doanh nghiệp, hãy gửi email cho chúng tôi:
[email được bảo vệ]

Báo cáo lỗi

Nếu bạn muốn báo cáo lỗi hoặc nếu bạn muốn đưa ra đề xuất, hãy gửi email cho chúng tôi:
[email được bảo vệ]

Example.com.vn được tối ưu hóa cho việc học tập và đào tạo. Các ví dụ có thể được đơn giản hóa để cải thiện khả năng đọc và học. Các hướng dẫn, tài liệu tham khảo và ví dụ liên tục được xem xét để tránh sai sót, nhưng chúng tôi không thể đảm bảo tính chính xác hoàn toàn của mọi nội dung. Khi sử dụng W3Schools, bạn đồng ý đã đọc và chấp nhận các điều khoản sử dụng , chính sách cookie và quyền riêng tư của chúng tôi.

Bản quyền 1999-2024 của Refsnes Data. Đã đăng ký Bản quyền. Example.com.vn được cung cấp bởi W3.CSS .