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

Պատկերացրեք, որ ղեկվարում եք մի ռոբոտի, որը գտնվում է գրաֆի某 դիրքում, որտեղ կա n κορուկ (գագաթ) և e կող։ Դուք ուզում եք սկսել某 գագաթից և հերթով անցնել գրաֆի բոլոր այն գագաթներով, որոնք հասանելի են սկզբնական կետից։ Depth First Search (DFS) ալգորիթմը հենց այդ նպատակին է ծառայում. այն սկսում է某 գագաթից, ընտրում է某 ճանապարհ ու գնում մինչև այն гագաթ, որտեղ այլևս հնարավոր չէ շարունակել, ապա “վերադառնում” է նախորդ գագաթ ու փորձում նոր ճանապարհներ։
Video preview
Տեսանյութ 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]
  1. ուսումնասիրում ենք 3-ի հարևաններին ⇒ [2]
  1. v = 2used = [False, False, True, True]
  1. ուսումնասիրում ենք 2-ի հարևաններին ⇒ [0, 1]
  1. v = 0used = [True, False, True, True]
  1. ուսումնասիրում ենք 0-ի հարևաններին ⇒ [1, 2]
  1. v = 1used = [True, True, True, True]
  1. ուսումնասիրում ենք 1-ի հարևաններին ⇒ [0, 2] ⇒ ամեն ինչ արդեն այցելված է
  1. բեքթրեք 1-ից
  1. բեքթրեք 0-ից
  1. բեքթրեք 2-ից
  1. բեքթրեք 3-ից → ավարտ
  1. 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]
  1. ուսումնասիրում ենք 0-ի հարևաններին ⇒ [1, 2]
  1. v = 1used = [True, True, False, False, False]
  1. ուսումնասիրում ենք 1-ի հարևաններին ⇒ [0, 2]
  1. v = 2used = [True, True, True, False, False]
  1. ուսումնասիրում ենք 2-ի հարևաններին ⇒ [0, 1] ⇒ արդեն բոլորն այցելված են
  1. բեքթրեք 2-ից
  1. բեքթրեք 1-ից
  1. բեքթրեք 0-ից → ավարտ
  1. Done
    1. 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]
  1. v = 1used = [T, T, F, F, F, F, F, F, F, F] ⇒ ուսումնասիրում ենք [0, 2, 3, 4]
  1. v = 2used = [T, T, T, F, F, F, F, F, F, F] ⇒ ուսումնասիրում ենք [0, 1]
  1. բեքթրեք 2-ից
  1. v = 1used = [T, T, T, F, F, F, F, F, F, F] ⇒ ուսումնասիրում ենք [x, x, 3, 4]
  1. v = 3used = [T, T, T, T, F, F, F, F, F, F] ⇒ ուսումնասիրում ենք [1, 5]
  1. v = 5used = [T, T, T, T, F, T, F, F, F, F] ⇒ ուսումնասիրում ենք [3, 6, 7, 8]
  1. v = 6used = [T, T, T, T, F, T, T, F, F, F] ⇒ ուսումնասիրում ենք [5]
  1. բեքթրեք 6-ից
  1. v = 7used = [T, T, T, T, F, T, T, T, F, F] ⇒ ուսումնասիրում ենք [5, 8]
  1. v = 8used = [T, T, T, T, F, T, T, T, T, F] ⇒ ուսումնասիրում ենք [5, 7, 9]
  1. v = 9used = [T, T, T, T, F, T, T, T, T, T] ⇒ ուսումնասիրում ենք [8]
  1. բեքթրեք 8-ից
  1. բեքթրեք 7-ից
  1. բեքթրեք 6-ից
  1. բեքթրեք 5-ից
  1. բեքթրեք 3-ից
  1. v = 1used = [T, T, T, T, F, T, T, T, T, T] ⇒ ուսումնասիրում ենք [x, x, x, 4]
  1. v = 4used = [T, T, T, T, T, T, T, T, T, T] ⇒ ուսումնասիրում ենք [1]
  1. բեքթրեք 4-ից
  1. բեքթրեք 1-ից
  1. բեքթրեք 0-ից
  1. 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