एल्गोरिथ्म्स और डेटा स्ट्रक्चर्स

डीप्थ फ़र्स्ट सर्च (DFS) алгорит्म

कल्पना कीजिए कि आप एक रोबोट को नियंत्रित कर रहे हैं जो किसी ग्राफ़ में स्थित है, जिसमें n वर्टिस और e एज हैं। आप एक शुरुआत वर्टिस से चलना चाहते हैं और धीरे-धीरे उन सभी वर्टिस को देखना चाहते हैं जो वहाँ से पहुँचे जा सकते हैं। DFS एल्गोरिदम ठीक यही करने में मदद करता है: आप एक वर्टिस से शुरू करते हैं, फिर एक निश्चित रास्ते को तब तक फ़ॉलो करते हैं जब तक आगे जाने का कोई रास्ता न बचे। उसके बाद, आप पीछे लौटते हैं (बैकट्रैक करते हैं) और फिर से कोई नया रास्ता खोजकर आगे बढ़ते हैं।
Video preview
वीडियो: Reducible - Depth First Search (DFS) Explained: Algorithm, Examples, and Code
DFS एल्गोरिदम को समझने का एक अच्छा तरीका यह है कि इस रोबोट के बारे में सोचें, जिसमें रोबोट केवल अपने वर्तमान वर्टिस के पड़ोसियों को और उन वर्टिस को देख सकता है जहाँ वह पहले जा चुका है (यानी वह अपनी पूरी यात्रा को याद रखता है)। यह एक रिकर्सिव प्रक्रिया है, जहाँ हर स्टेप में रोबोट किसी नए वर्टिस पर जाता है जो अभी तक विज़िट नहीं हुआ, और इसी तरह दोहराता रहता है जब तक उस रास्ते में कोई नया वर्टिस न बचे। फिर वह पीछे लौटता है और पिछले वर्टिस से बाकी बचे रास्तों को एक्सप्लोर करता है। इस तरह की “रोबोट” वाली सोच वास्तव में इसे इम्प्लीमेंट करने में मदद करती है।
नीचे दिखाया गया DFS एल्गोरिदम एक रिकर्सिव प्रक्रिया का बेहतरीन उदाहरण है। इस इम्प्लीमेंटेशन में हम एक करंट वर्टिस (जिसे हम v कहते हैं) और उन सभी वर्टिस को ट्रैक करते हैं जिन्हें हमने अब तक विज़िट किया है (इसे used कहते हैं):
import sys

sys.setrecursionlimit(10 ** 6)          # DFS सुचारू रूप से चले, इसलिए recursion limit बढ़ा रहे हैं

n, e = map(int, input().split())        # n: vertices, e: edges
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):                             # depth-first search
    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 कॉल
ऊपर दिए हुए कोड में सबसे पहले हम अपने ग्राफ़ को इनिशियलाइज़ करते हैं और उसके बाद start वर्टिस से ग्राफ़ ट्रावर्स करना शुरू करते हैं। शुरू में, सभी used मान False होते हैं। जब हम किसी वर्टिस को विज़िट करते हैं, तो used[v] = True करके उसे मार्क करते हैं और फिर उसके सभी पड़ोसी वर्टिस को देखते हैं।
जब कोई रास्ता पूरी तरह एक्सप्लोर हो जाता है, तो रिकर्सन हमें अपने पिछले वर्टिस पर वापस ले आता है, ताकि हम वहाँ से बाकी पड़ोसियों को देख सकें। इस तरह वापस लौटने की प्रक्रिया को बैकट्रैकिंग कहते हैं।
आइए अब कुछ इनपुट्स पर इस एल्गोरिदम को स्टेप-बाइ-स्टेप देखते हैं:
n = 4, e = 4
इनपुट a, b पेयर्स: [(0, 1), (0, 2), (1, 2), (3, 2)]
शुरुआती वर्टिस 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 से बैकट्रैक ⇒ DFS समाप्त
  1. Done
n = 5, e = 4
इनपुट a, b पेयर्स: [(0, 1), (0, 2), (1, 2), (3, 4)]
शुरुआती वर्टिस 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 से बैकट्रैक ⇒ DFS समाप्त
  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 (वीडियो वाला उदाहरण)
इनपुट a, b पेयर्स: [(0, 1), (0, 2), (1, 2), (1, 4), (1, 3), (3, 5), (6, 5), (5, 8), (5, 7), (7, 8), (8, 9)]
शुरुआती वर्टिस 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
 

चुनौती: किसी ग्राफ़ में कनेक्टेड कंपोनेंट्स की संख्या निकालें

आपके पास एक undirected ग्राफ़ है जिसमें v वर्टिस और e एज हैं। आपका काम है इस ग्राफ़ में कनेक्टेड कंपोनेंट्स की संख्या निकालना। एक कनेक्टेड कंपोनेंट का मतलब ऐसे वर्टिस का समूह है, जिनके बीच जाने-आने का रास्ता मौजूद हो।

इनपुट

इनपुट की पहली लाइन में दो पूर्णांक v (1 ≤ v ≤ 100 000) और e (1 ≤ e ≤ 100 000) दिए होते हैं।
अगली e पंक्तियों में प्रत्येक में दो पूर्णांक v1, v2 (1 ≤ v1, v2 ≤ v) दिए होते हैं, जिनका मतलब है कि v1 वर्टिस v2 से कनेक्टेड है और विपरीत भी।

आउटपुट

कार्यक्रम को ग्राफ़ में कनेक्टेड कंपोनेंट्स की संख्या प्रिंट करनी चाहिए।

Examples

इनपुट
आउटपुट
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