Depth First Search (DFS) ալգորիթմ

Պատկերացրեք, որ ղեկվարում եք մի ռոբոտի, որը գտնվում է գրաֆի某 դիրքում, որտեղ կա n κορուկ (գագաթ) և e կող։ Դուք ուզում եք սկսել某 գագաթից և հերթով անցնել գրաֆի բոլոր այն գագաթներով, որոնք հասանելի են սկզբնական կետից։ Depth First Search (DFS) ալգորիթմը հենց այդ նպատակին է ծառայում. այն սկսում է某 գագաթից, ընտրում է某 ճանապարհ ու գնում մինչև այն гագաթ, որտեղ այլևս հնարավոր չէ շարունակել, ապա “վերադառնում” է նախորդ գագաթ ու փորձում նոր ճանապարհներ։

Տեսանյութ Reducible ալիքից – Depth First Search (DFS)-ի բացատրություն: Ալգորիթմ, օրինակներ և կոդ

DFS ալգորիթմը պատկերացնելիս կարելի է մտածել փոքրիկ ռոբոտի մասին, որը սկսում է某 գագաթից և տեսնում է միայն текմ الحالية գագաթի հարևաններին և այն գագաթները, ուր ինքն արդեն գնացել է (և հիշում է այդ ողջ ճանապարհը): Այս պրոցեսը ռեկուրսիվ է. յուրաքանչյուր փուլում ռոբոտը գնալու է某 նոր գագաթ, որտեղ դեռ չի եղել, ու նույնը կրկնելու է մինչև այլևս չլինեն չայցելված գագաթներ այդ ուղղությամբ։ Հետո ռոբոտը “վերադառնում” է նախորդ կետ, որպեսզի շարունակի նույն գագաթի մնացած հարևանների ուսումնասիրությունը։ Այս միտքը շատ է օգնում ալգորիթմի իրականացմամբ (ռեալիզացիայով) զբաղվելիս։

DFS ալգորիթմի իրագործումը կարելի է անել ռեկուրսիայի միջոցով, որտեղ մենք հետևում ենք текущ гագաթին (նշենք այն v-ով), ինչպես նաև այն գագաթների ցուցակին, որոնք արդեն օգտագործվել են (նշենք used-ով).

import sys

sys.setrecursionlimit(10 ** 6)          # Մեծացնում ենք ռեկուրսիայի սահմանը, որպեսզի DFS-ն աշխատի առանց խնդիրների

n, e = map(int, input().split())        # n: գագաթների քանակը, e: կողերի քանակը
g = [[] for _ in range(n)]              # գրաֆի adjacency list ներկայացում
used = [False] * n                      # այցելված (օգտագործված) գագաթներ

for _ in range(e):                      # ընթերցում ենք կողերը
    a, b = map(int, input().split())    # a -> b և b -> a (անուղղորդ գրաֆ)
    g[a].append(b)
    g[b].append(a)


def dfs(v):                             # խորությամբ որոնում
    used[v] = True                      # նշում ենք, որ գագաթը այցելված է
    print(v, end=' ')                   # տպում ենք գագաթը
    for to in g[v]:                     # անցնում ենք v-ի բոլոր հարևաններով
        if not used[to]:                # եթե գագաթը դեռ չի օգտագործվել
            dfs(to)                     # անում ենք dfs այդ գագաթի համար


start = int(input())                    # մեկնարկային գագաթ
dfs(start)                              # կանչում ենք dfs մեկնարկային գագաթի համար

Առաջին հերթին սկզբնական փուլում初始化 ենք գրաֆը, ևTraversal-ը սկսում ենք start գագաթից։ Սկզբում used զանգվածի բոլոր արժեքները False են։ Երբ այցելում ենք某 գագաթ, սկզբում դրան նշանակում ենք used[v] = True (նշելով, որ այն արդեն այցելված է), հետո անցնում ենք текущ գագաթի v բոլոր հարևաններին։

Ուշադրություն դարձրեք, թե ինչպես է ռեկուրսիան գործում որպես “ճանապարհի” ուսումնասիրող․ երբ ալգորիթմը “չունի” էլ հետագա չիրացվող գագաթներ某 ուղղությամբ, այն վերադառնում է (բեքթրեք) նախորդ դրվագի գագաթ, որպեսզի այնտեղից继续 ուսումնասիրել մնացած հարևանները։ Այդ բեքթրեքն էլ հենց ռեկուրսիայի ավարտման պահն է։

Եկեք մոդելավորենք ալգորիթմի գործողությունը մի քանի օրինակով.

n = 4, e = 4

The input a, b pairs are the following: [(0, 1), (0, 2), (1, 2), (3, 2)]

The starting vertex is 3

  1. v = 3used = [False, False, False, True]

  2. ուսումնասիրում ենք 3-ի հարևաններին ⇒ [2]

  3. v = 2used = [False, False, True, True]

  4. ուսումնասիրում ենք 2-ի հարևաններին ⇒ [0, 1]

  5. v = 0used = [True, False, True, True]

  6. ուսումնասիրում ենք 0-ի հարևաններին ⇒ [1, 2]

  7. v = 1used = [True, True, True, True]

  8. ուսումնասիրում ենք 1-ի հարևաններին ⇒ [0, 2] ⇒ ամեն ինչ արդեն այցելված է

  9. բեքթրեք 1-ից

  10. բեքթրեք 0-ից

  11. բեքթրեք 2-ից

  12. բեքթրեք 3-ից → ավարտ

  13. Done

n = 5, e = 4

The input a, b pairs are the following: [(0, 1), (0, 2), (1, 2), (3, 4)]

The starting vertex is 0

  1. v = 0used = [True, False, False, False, False]

  2. ուսումնասիրում ենք 0-ի հարևաններին ⇒ [1, 2]

  3. v = 1used = [True, True, False, False, False]

  4. ուսումնասիրում ենք 1-ի հարևաններին ⇒ [0, 2]

  5. v = 2used = [True, True, True, False, False]

  6. ուսումնասիրում ենք 2-ի հարևաններին ⇒ [0, 1] ⇒ արդեն բոլորն այցելված են

  7. բեքթրեք 2-ից

  8. բեքթրեք 1-ից

  9. բեքթրեք 0-ից → ավարտ

  10. Done

    Notice how nodes 3 and 4 were never visited.

    They were not connected to the initial node 0.

n = 10, e = 11 (example from the video)

The input a, b pairs are the following: [(0, 1), (0, 2), (1, 2), (1, 4), (1, 3), (3, 5), (6, 5), (5, 8), (5, 7), (7, 8), (8, 9)]

The starting vertex is 0

  1. v = 0used = [T, F, F, F, F, F, F, F, F, F] ⇒ ուսումնասիրում ենք [1, 2]

  2. v = 1used = [T, T, F, F, F, F, F, F, F, F] ⇒ ուսումնասիրում ենք [0, 2, 3, 4]

  3. v = 2used = [T, T, T, F, F, F, F, F, F, F] ⇒ ուսումնասիրում ենք [0, 1]

  4. բեքթրեք 2-ից

  5. v = 1used = [T, T, T, F, F, F, F, F, F, F] ⇒ ուսումնասիրում ենք [x, x, 3, 4]

  6. v = 3used = [T, T, T, T, F, F, F, F, F, F] ⇒ ուսումնասիրում ենք [1, 5]

  7. v = 5used = [T, T, T, T, F, T, F, F, F, F] ⇒ ուսումնասիրում ենք [3, 6, 7, 8]

  8. v = 6used = [T, T, T, T, F, T, T, F, F, F] ⇒ ուսումնասիրում ենք [5]

  9. բեքթրեք 6-ից

  10. v = 7used = [T, T, T, T, F, T, T, T, F, F] ⇒ ուսումնասիրում ենք [5, 8]

  11. v = 8used = [T, T, T, T, F, T, T, T, T, F] ⇒ ուսումնասիրում ենք [5, 7, 9]

  12. v = 9used = [T, T, T, T, F, T, T, T, T, T] ⇒ ուսումնասիրում ենք [8]

  13. բեքթրեք 8-ից

  14. բեքթրեք 7-ից

  15. բեքթրեք 6-ից

  16. բեքթրեք 5-ից

  17. բեքթրեք 3-ից

  18. v = 1used = [T, T, T, T, F, T, T, T, T, T] ⇒ ուսումնասիրում ենք [x, x, x, 4]

  19. v = 4used = [T, T, T, T, T, T, T, T, T, T] ⇒ ուսումնասիրում ենք [1]

  20. բեքթրեք 4-ից

  21. բեքթրեք 1-ից

  22. բեքթրեք 0-ից

  23. Done

Առաջադրանք: Հաշվել գրաֆում կապված կոմպոնենտների քանակը

Տրված է անուղղորդ գրաֆ, որն ունի v գագաթ և e կող։ Պահանջվում է հաշվել գրաֆի կապված կոմպոնենտների քանակը։ Եթե某 միավոր գագաթներ փոխադարձ անցումներով հասանելի են մեկը մյուսին, ապա դրանք պատկանում են同 կապված կոմպոնենտին։

Մուտք

Մուտքի առաջին տողում ներառված են երկու ամբողջ թվեր v (1 ≤ v ≤ 100 000) և e (1 ≤ e ≤ 100 000):

Հաջորդ e տողերում տրվում են զույգերով թվեր v1, v2 (1 ≤ v1, v2 ≤ v), որոնք նշում են, որ գագաթ v1-connected է գագաթ v2-ին և հակառակը։

Ելք

Ծրագիրը պետք է տպի գրաֆի կապված կոմպոնենտների քանակը։

Օրինակներ

Մուտք

Ելք

7 6 1 2 2 3 1 3 4 5 5 6 4 6

3

2 1 1 2

1

2 0

2

Constraints

Time limit: 5 seconds

Memory limit: 512 MB

Output limit: 1 MB

To check your solution you need to sign in
Sign in to continue