Snuc1925
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    - Thuật toán DFS/BFS: Intro: Chắc hẳn các cậu đều đã nghe qua bài toán: "7 cây cầu" của Euler. Đây là một bài toán nổi tiếng về lý thuyết đồ thị. Đồ thị là một tập các đối tượng có quan hệ với nhau theo một cách nào đó. Chẳng hạn như trong khoa học máy tính, đồ thị được sử dụng để mô hình hóa một mạng truyền thông, kiến trúc của các máy tính song song,... Bài toán tối ưu đường đi giao hàng trong các công ty thương mại lớn như Shopee, Tiki,... cũng có thể biểu diễn dưới dạng đồ thị. Chính vì vậy, việc nắm vững các thuật toán liên quan đến đồ thị là điều hết sức quan trọng đối với mỗi lập trình viên. Hôm nay, Mely xin giới thiệu đến các cậu 2 thuật toán duyệt đồ thị cơ bản đó là: DFS và BFS. https://www.canva.com/design/DAFxVXaUxsY/3isgr9EJtLaHh1Iae6vzrA/edit (Thêm vào caption ở ảnh trên) * Tô màu các đỉnh trong video: Đỉnh có viền xanh: Đỉnh đang được gọi đệ quy Đỉnh có nền xanh: Đỉnh đang xét Đỉnh có viền vàng: Đỉnh đã thăm Ví dụ đồ thị như trong video. Giả sử đỉnh bắt đầu là đỉnh 0. Khi đó: Một cách duyệt DFS có thể là: - Xét đỉnh 1 kề với đỉnh 0, do đỉnh 1 chưa được tới thăm nên di chuyển đến đỉnh 1. - Tương tự, di chuyển đến đỉnh 2 rồi đến đỉnh 3. - Từ đỉnh 3, ta có đường đi nối đến đỉnh 1, tuy nhiên đỉnh 1 đã được thăm rồi, nên ta quay lại đỉnh 2, sau đó quay lại đỉnh 1, đỉnh 0. - Từ đỉnh 0 ta tiếp tục tới thăm đỉnh 4. - Đỉnh 4 có đường nối đến đỉnh 3, vì đỉnh 3 đã được thăm trước đó nên ta quay lại đỉnh 0. - Từ đỉnh 0 đến thăm đỉnh 5. Lúc này, tất cả các điểm đều đã được duyệt qua. Thuật toán kết thúc. ---------- Breadth-first search (BFS): Table of contents: 1. BFS là gì? - Thuật toán duyệt đồ thị ưu tiên chiều rộng (Breath-first search) là một trong những thuật toán tìm kiếm cơ bản và cần thiết trên đồ thị. Trong mỗi lần thực hiện, thuật toán ưu tiên duyệt những đỉnh gần đỉnh đang xét trước. Đường đi thu được từ thuật toán BFS tới bất kỳ đỉnh nào là đường đi ngắn nhất tới đỉnh đó, tức là đường đi chứa số cạnh nhỏ nhất trên đồ thị không có trọng số. - Thuật toán được áp dụng để giải nhiều bài toán khác nhau như tìm tất cả các đỉnh có thể duyệt được từ một đỉnh cho trước, kiểm tra tính liên thông của đồ thị, tìm (trong đồ thị không có trọng số) đường đi ngắn nhất từ một đỉnh tới tất cả các đỉnh khác, xác định xem đồ thị có phải là đồ thị hai phía (bipartite graph) hay không, tìm đường kính (diameter) của đồ thị vô hướng... - Giống như0 thuật toán DFS, BFS có thể áp dụng cho cả đồ thị có hướng và đồ thị vô hướng. 2. BFS hoạt động thế nào? Các bước ra sao? Cho trước một đồ thị không có trọng số và đỉnh nguồn s. Ta định nghĩa level(i) là cấp của đỉnh i, nghĩa là độ dài đường đi ngắn nhất từ đỉnh nguồn s đến đỉnh i. Thuật toán có thể được hiểu như một ngọn lửa lan rộng trên đồ thị: Ban đầu, ngọn lửa bốc cháy tại đỉnh nguồn s. Ở mỗi bước, ngọn lửa lan rộng từ đỉnh này sang các tất cả đỉnh khác liền kề với nó. Trong mỗi lần lặp của thuật toán, “vòng lửa” lại lan rộng theo chiều rộng. Các đỉnh có chung một level sẽ được ưu tiên duyệt trước, sau đó mới duyệt đến các đỉnh ở level cao hơn. (xem hình) Ta cần một cấu trúc dữ liệu queue (hàng đợi) để chứa danh sách những đỉnh đang “chờ” thăm. Tại mỗi bước, ta thăm một đỉnh đầu hàng đợi, loại nó ra khỏi danh sách và cho những đỉnh kề với nó chưa được thăm xếp hàng vào cuối hàng đợi. Thuật toán sẽ kết thúc khi hàng đợi rỗng và lúc đó, tất cả các đỉnh của đồ thị đã được duyệt. Một cách cụ thể hơn, Ta cần một hàng đợi queue để lưu trữ các đỉnh cần được thăm và một mảng boolean visited[]  cho biết mỗi đỉnh đã được thăm hay chưa. Ban đầu, ta thêm  s  vào queue và đặt  visited[s] = true , và đối với tất cả các đỉnh i khác s, ta đặt  visited[i] = false . Thực hiện lặp lại các bước sau cho đến khi queue rỗng: • Lấy ra phần tử đầu tiên của hàng đợi, gọi là u • Duyệt lần lượt tất cả các đỉnh liền kề với u, gọi chung là v • Đối với mỗi đỉnh v, kiểm tra xem v đã được thăm trước đó chưa (visited[v] = true hay là false) • Nếu  v chưa được thăm trước đó (visited[v] = false), ta đánh dấu đỉnh đó là đã thăm (visted[v] = true) và thêm v vào cuối queue. Vòng lặp kết thúc khi queue trống. Mảng visited[] với tất cả các giá trị true cho ta biết tất cả các đỉnh đã được thăm. Tuy nhiên, với thông tin này ta chỉ mới biết được từ một đỉnh s thì ta có thể đi đến thăm được một đỉnh nào đó trong đồ thị mà chưa biết độ dài đường đi ngắn nhất của giữa chúng và đường đi đó đi qua những điểm nào. Để xử lí điều này, ta chỉ cần duy trì một mảng level[] (như đã đề cập ở trên) và truy vết đường đi bằng cách duy trì một mảng parent[] khác. Ta gán level[s] = 0. Vì đỉnh nguồn không có điểm nào tới được điểm đó nên ta cũng gán parent[s] = -1. Ở mỗi bước, ta nhận thấy rằng mỗi đỉnh v nếu chưa được thăm trước đó thì chỉ có thể được thăm bởi u. Vì vậy ta có level[v] = level[u] + 1 và parent[v] = u. Sau cùng, ta có level[i] chứa độ dài ngắn nhất để từ đỉnh nguồn s, ta tới được i. Đối với đường đi, đơn giản ta chỉ cần xuất phát ngược từ đỉnh mà ta muốn xét, in ra parent của nó và lặp lại cho đến khi parent của nó = -1 (nghĩa là ta đã duyệt đến đỉnh nguồn). Code mẫu: https://ideone.com/w30RL5 ** Giải thích ví dụ trong video: * Tô màu các đỉnh trong video: Đỉnh có viền xanh: Đỉnh trong hàng đợi (đỉnh đang được chờ thăm) Đỉnh có nền xanh: Đỉnh đang xét Đỉnh có viền vàng: Đỉnh đã thăm * Giải thích thuật toán: Ta có đồ thị vô hướng như trong video và đỉnh nguồn là đỉnh 0. Gọi hàng đợi là q. Khi đó, thuật toán BFS sẽ được thực hiện như sau: - Đánh dấu đỉnh 0 đã thăm, đặt đỉnh 0 vào hàng đợi. q = {0} - Lấy ra đỉnh 0 từ đầu hàng đợi, xét đỉnh kề với đỉnh 0 là đỉnh 1: vì đỉnh 1 chưa thăm nên ta đánh dấu nó là đã thăm và đặt đỉnh 1 vào hàng đợi. q = {1} - Lấy ra đỉnh 1 từ đầu hàng đợi, xét 3 đỉnh kề với đỉnh 1 là đỉnh 2, 3, 4: + Đỉnh 2 chưa thăm, đánh dấu là đã thăm và đặt đỉnh 2 vào hàng đợi. + Tương tự, đỉnh 3 và 4 chưa được thăm, đánh dấu 2 đỉnh là đã thăm và đặt 2 đỉnh vào hàng đợi. + Lúc này, q = {2, 3, 4} - Lấy ra đỉnh 2 từ đầu hàng đợi, xét 2 đỉnh kề với đỉnh 2 là 1, 3: + Đỉnh 1 đã thăm nên ta bỏ qua đỉnh này. + Tương tự, đỉnh 3 cũng đã thăm nên ta cũng bỏ qua đỉnh này. + Lúc này, q = {3, 4} - Lấy ra đỉnh 3 từ đầu hàng đợi, xét 3 đỉnh kề với đỉnh 3 là 1, 2, 5: + Đỉnh 1, 2 đã thăm nên ta bỏ qua 2 đỉnh này. + Đỉnh 5 chưa thăm, ta đánh dấu đã thăm và đặt đỉnh 5 và hàng đợi. + Lúc này, q = {4, 5} - Lấy ra đỉnh 4 từ đầu hàng đợi, xét đỉnh kề với đỉnh 4 là đỉnh 1. Đỉnh 1 đã thăm nên ta bỏ qua đỉnh này. q = {5} - Lấy ra đỉnh 5 từ đầu hàng đợi, xét 2 đỉnh kề với đỉnh 5 là đỉnh 3, 6: + Đỉnh 3 đã thăm nên ta bỏ qua đỉnh này + Đỉnh 6 chưa thăm, ta đánh dấu đã thăm và đặt đỉnh 6 và hàng đợi. + Lúc này, q = {6} - Lấy ra đỉnh 6 từ đầu hàng đợi, xét đỉnh kề với đỉnh 6 là đỉnh 5. Đỉnh 5 đã thăm nên ta bỏ qua đỉnh này. - Lúc này hàng đợi q đã rỗng, kết thúc thuật toán. 3. Đánh giá độ phức tạp Ta gọi |V| là số lượng đỉnh và |E| là số lượng cạnh của đồ thị. Độ phức tạp của thuật toán: Nếu ta sử dụng ma trận kề (adjacency matrix) để biểu diễn thuật toán, độ phức tạp sẽ là O(|V|^2). Tuy nhiên, khi sử dụng danh sách kề (adjacency list), thuật toán chỉ mất độ phức tạp O(|V| + |E|). Sở dĩ ta có điều này vì với danh sách kề ta có khả năng duyệt qua các đỉnh kề của mỗi đỉnh một cách hiệu quả (tối ưu về mặt thời gian). Ta nhận thấy queue không bao giờ vượt quá |V| phần tử. Vì vậy độ phức tạp không gian sẽ là O(|V|). 4. Một số ứng dụng của BFS (optional, vắn tắt) Dưới đây là một số bài toán có thể giải bằng BFS: * Tìm tất cả các thành phần liên thông của đồ thị. * Tìm đường đi ngắn nhất trong đồ thị có trọng số 0 hoặc 1 (bài toán 0-1 BFS). * Tìm chu kỳ ngắn nhất trong đồ thị có hướng không trọng số. * Tìm tất cả các cạnh hoặc đỉnh nằm trên bất kỳ đường đi ngắn nhất nào giữa một cặp đỉnh nhất định. <!-- Reference documents: https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-fall-2011/resources/lecture-13-breadth-first-search-bfs/ https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/196a95604877d326c6586e60477b59d4_MIT6_006S20_lec9.pdf (two main rfs) https://cp-algorithms.com/graph/breadth-first-search.html (for cp) https://www.cs.cmu.edu/afs/cs/academic/class/15210-s15/www/lectures/bfs-notes.pdf (advanced terms) https://www.slideshare.net/ShuvongkorBarman/presentation-on-breadth-first-search-bfs (for diagram examples) --> Nội dung cho slide bfs: 1. BFS là gì a) Nhà phát minh - BFS và ứng dụng của nó trong bài toán tìm các thành phần liên thông trên đồ thị được nhà kỹ sư khoa học máy tính người Đức, Konrad Zuse phát minh vào năm 1945. - Ngoài đóng góp trên, ông cũng có thành tựu tạo ra chiếc máy tính lập trình đầu tiên trên thế giới Z3 được điều khiển bằng chương trình, bắt đầu hoạt động vào tháng 5 năm 1941. b) BFS là gì - Thuật toán duyệt đồ thị ưu tiên chiều rộng (Breath-first search) là một trong những thuật toán tìm kiếm cơ bản và cần thiết trên đồ thị. Trong mỗi lần thực hiện, thuật toán ưu tiên duyệt những đỉnh gần đỉnh đang xét trước mà có cạnh nối từ đỉnh đang xét đến nó. Đường đi thu được từ thuật toán BFS tới bất kỳ đỉnh nào là đường đi ngắn nhất tới đỉnh đó, tức là đường đi chứa số cạnh nhỏ nhất trên đồ thị không có trọng số. - Thuật toán được áp dụng để giải nhiều bài toán khác nhau như tìm tất cả các đỉnh có thể duyệt được từ một đỉnh cho trước, kiểm tra tính liên thông của đồ thị, tìm (trong đồ thị không có trọng số) đường đi ngắn nhất từ một đỉnh tới tất cả các đỉnh khác, xác định xem đồ thị có phải là đồ thị hai phía (bipartite graph) hay không, tìm đường kính (diameter) của đồ thị vô hướng... - Giống như thuật toán DFS, BFS có thể áp dụng cho cả đồ thị có hướng và đồ thị vô hướng. 2. Ví dụ về một cách duyệt: Giải thích thông qua hình => giải thích cấp (level) của đỉnh 3. Mô tả thuật toán - Lấy ra một ví dụ chứa cycle và giải thích tầm quan trọng của việc đánh dấu điểm đã thăm - Làm sao để lưu trữ các đỉnh được chờ thăm? => sử dụng cấu trúc dữ liệu + Khi ta duyệt một đỉnh, ta không lập tức duyệt tiếp các lân cận của nó luôn mà cần phải xét hết tất cả các đỉnh cùng level với nó trước. => cấu trúc này phải đảm bảo rằng các đỉnh của cùng 1 level phải được xét trước khi duyệt tới các level sau. => điều này dẫn tới việc ta liên tưởng đến cấu trúc dữ liệu hàng đợi sử dụng phương pháp FIFO (first in first out). Cho một đồ thị vô hướng và một đỉnh nguồn s cho trước. BFS sẽ tuân theo 3 quy tắc đơn giản sau: Quy tắc 1: Từ đỉnh đang xét, đi thăm đỉnh chưa thăm liền kề. Đánh dấu nó là đã thăm. In ra đỉnh đó và thêm nó vào hàng đợi. Quy tắc 2: Nếu không tìm thấy đỉnh thỏa mãn, loại bỏ đỉnh đó khỏi hàng đợi. Quy tắc 3 : Lặp lại Quy tắc 1 và Quy tắc 2 cho đến khi hàng đợi trống. Lúc này, toàn bộ đồ thị đã được duyệt qua, thuật toán kết thúc. Tuy nhiên, với thông tin này ta chỉ mới biết được từ một đỉnh s thì ta có thể đi đến thăm được một đỉnh nào đó trong đồ thị mà chưa biết độ dài đường đi ngắn nhất của giữa chúng và đường đi đó đi qua những điểm nào. Để xử lí điều này, ta chỉ cần duy trì một mảng level[] (như đã đề cập ở trên) và truy vết đường đi bằng cách duy trì một mảng parent[] khác. Ta gán level[s] = 0. Vì đỉnh nguồn không có điểm nào tới được điểm đó nên ta cũng gán parent[s] = -1. Ở mỗi bước, ta nhận thấy rằng mỗi đỉnh v nếu chưa được thăm trước đó thì chỉ có thể được thăm bởi u. Vì vậy ta có level[v] = level[u] + 1 và parent[v] = u. Sau cùng, ta có level[i] chứa độ dài ngắn nhất để từ đỉnh nguồn s, ta tới được i. Đối với đường đi, đơn giản ta chỉ cần xuất phát ngược từ đỉnh mà ta muốn xét, in ra parent của nó và lặp lại cho đến khi parent của nó = -1 (nghĩa là ta đã duyệt đến đỉnh nguồn). => Ví dụ về thuật toán trên một đồ thị cụ thể Tìm tất cả các thành phần liên thông của đồ thị. Tìm tất cả các cạnh hoặc đỉnh nằm trên bất kỳ đường đi ngắn nhất nào giữa một cặp đỉnh nhất định.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully