3338 - disjoint: Difference between revisions

From Bitnami MediaWiki
Pagină nouă: == Cerinţa == Răspundeți la toate întrebările de al doilea tip, în ordinea acestora. == Date de intrare == Programul citește de la tastatură numerele '''N''' și '''M''', iar apoi '''M''' triplete de numere naturale de forma '''op x y''', unde '''op''' poate lua doar valorile 1 și 2, aceste triplete reprezentând câte o operație. == Date de ieşire == Programul va afișa pe ecran, pe câte o linie, răspunsul la fiecare întrebare de tip '''2'''. Dacă la întrebar...
 
No edit summary
 
(2 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Se consideră N copii, numerotați de la 1 la N și fiecare face parte dintr-o clasă. Inițial sunt n clase și fiecare copil face parte din propria sa clasă. Se dau M operații de două tipuri:
<br>
* 1 x y – acțiune: clasele din care fac parte copiii cu numerele x și y se reunesc. Dacă x și y fac deja parte din aceeași clasă, operația nu se efectuează
<br>
* 2 x y – întrebare: copiii cu numerele x și y sunt sau nu în aceeași clasă?
== Cerinţa ==
== Cerinţa ==
Răspundeți la toate întrebările de al doilea tip, în ordinea acestora.
Răspundeți la toate întrebările de al doilea tip, în ordinea acestora.
== Date de intrare ==
== Date de intrare ==
Programul citește de la tastatură numerele '''N''' și '''M''', iar apoi '''M''' triplete de numere naturale de forma '''op x y''', unde '''op''' poate lua doar valorile 1 și 2, aceste triplete reprezentând câte o operație.
Programul citește de la tastatură numerele '''N''' și '''M''', iar apoi '''M''' triplete de numere naturale de forma '''op x y''', unde '''op''' poate lua doar valorile 1 și 2, aceste triplete reprezentând câte o operație.
Line 9: Line 15:
* '''2 ≤ M ≤ 2000'''
* '''2 ≤ M ≤ 2000'''
* va exista cel puțin o operație de tip '''1''' și cel puțin o operație de tip '''2'''.
* va exista cel puțin o operație de tip '''1''' și cel puțin o operație de tip '''2'''.
== Exemplu ==
== Exemplul 1 ==
; Intrare
; Intrare
: 6 6
: 6 6
Line 19: Line 25:
: 2 1 6
: 2 1 6
; Ieșire
; Ieșire
: Datele introduse corespund restricțiilor impuse.
: NU
: NU
: DA
: DA
: DA
: DA
== Exemplul 2 ==
; Intrare
: 6 6
: 1 1 4
: 1 3 6
: 2 4 6
: 1 1 3
: 2 4 6
: 2 1 520
; Ieșire
: Datele introduse nu corespund restricțiilor impuse.
== Explicație ==
== Explicație ==
Sunt '''6''' copii și '''6''' operații. După primele două operații, elevii '''1''' și '''4''' sunt în aceeași clasă și '''3''' și '''6''' sunt în aceeași clasă. La întrebarea '''2 4 6''' răspunsul este evident '''NU'''. La a patra operație '''1''' și '''3''' sunt trecuți în aceeași clasă, deci va exista o clasă cu '''4''' copii: '''{1,3,4,6}''', deci la ultimele două întrebări acum răspunsul este '''DA''' la ambele.
Sunt '''6''' copii și '''6''' operații. După primele două operații, elevii '''1''' și '''4''' sunt în aceeași clasă și '''3''' și '''6''' sunt în aceeași clasă. La întrebarea '''2 4 6''' răspunsul este evident '''NU'''. La a patra operație '''1''' și '''3''' sunt trecuți în aceeași clasă, deci va exista o clasă cu '''4''' copii: '''{1,3,4,6}''', deci la ultimele două întrebări acum răspunsul este '''DA''' la ambele.
== Rezolvare ==
== Rezolvare ==
<syntaxhighlight lang="python" line>
<syntaxhighlight lang="python" line>
# Funcția 'find' returnează reprezentantul (sau liderul) al setului în care se află un element dat.
# 3338 - disjoint
def find(parent, i):
def validare(n, m, operati):
     if parent[i] == i:
    # Verificăm dacă N și M sunt în limitele specificate și dacă avem numărul corect de operații
         return i
    if n < 1 or n > 500 or m < 2 or m > 2000 or len(operati) != m:
     return find(parent, parent[i])
        raise ValueError
     tip1 = tip2 = False
    for op, x, y in operati:
        # Verificăm dacă există cel puțin o operație de fiecare tip
        if op == 1:
            tip1 = True
        elif op == 2:
            tip2 = True
        # Verificăm dacă operațiile sunt valide
         if op not in [1, 2] or x < 1 or x > n or y < 1 or y > n:
            raise ValueError
     # Verificăm dacă există cel puțin o operație de fiecare tip
    if not (tip1 and tip2):
        raise ValueError


# Funcția 'union' este utilizată pentru a uni două seturi.
     print("Datele de intrare corespund restrictiilor impuse")
def union(parent, rank, x, y):
     return True
     xroot = find(parent, x)
     yroot = find(parent, y)


    # Atașează arborele mai mic la rădăcina celui mai mare
    if rank[xroot] < rank[yroot]:
        parent[xroot] = yroot
    elif rank[xroot] > rank[yroot]:
        parent[yroot] = xroot
    else :
        parent[yroot] = xroot
        rank[xroot] += 1


# Funcția 'solve' citește datele de intrare și rezolvă problema.
# Funcția 'rezolvare' rezolvă problema dată
def solve():
def rezolvare(n, _, operati):
     N, M = map(int,input().strip().split())
     # Inițializăm părinții și rangurile
     parent = [i for i in range(N+1)]
     parent = [i for i in range(n + 1)]
     rank = [0 for _ in range(N+1)]
     rank = [0 for _ in range(n + 1)]
     res = []
     res = []
      
 
     for _ in range(M):
     # Funcția 'find' găsește reprezentantul unui element
         op, x, y = map(int,input().strip().split())
     def find(i):
         if parent[i] == i:
            return i
        return find(parent[i])
 
    # Funcția 'union' unește două seturi
    def union(x1, y2):
        xroot = find(x1)
        yroot = find(y2)
 
        # Atașăm arborele mai mic la rădăcina celui mai mare
        if rank[xroot] < rank[yroot]:
            parent[xroot] = yroot
        elif rank[xroot] > rank[yroot]:
            parent[yroot] = xroot
        else:
            parent[yroot] = xroot
            rank[xroot] += 1
 
    # Parcurgem operațiile și le aplicăm
    for op, x, y in operati:
         if op == 1:
         if op == 1:
             union(parent, rank, x, y)
             union(x, y)
         else:
         else:
             # Dacă x și y au același părinte (adică sunt în aceeași clasă), atunci afișează 'DA'
             # Dacă x și y au același părinte, atunci sunt în aceeași clasă
             if find(parent, x) == find(parent, y):
             if find(x) == find(y):
                 res.append('DA')
                 res.append('DA')
             else:
             else:
                 res.append('NU')
                 res.append('NU')
      
 
     # Afișăm rezultatele
     print('\n'.join(res))
     print('\n'.join(res))


# Acest cod va fi executat doar dacă scriptul este rulat direct
# Acest cod va fi executat doar dacă scriptul este rulat direct
if __name__ == "__main__":
if __name__ == '__main__':
     solve()
    try:
        # Citim datele de intrare
        N, M = map(int, input().strip().split())
        operatii = [list(map(int, input().strip().split())) for _ in range(M)]
        # Validăm datele de intrare
        validare(N, M, operatii)
        # Rezolvăm problema
        rezolvare(N, M, operatii)
    # Tratăm eventualele erori
     except ValueError:
        print("Datele de intrare nu corespund restrictiilor impuse")


</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 14:19, 9 December 2023

Se consideră N copii, numerotați de la 1 la N și fiecare face parte dintr-o clasă. Inițial sunt n clase și fiecare copil face parte din propria sa clasă. Se dau M operații de două tipuri:

  • 1 x y – acțiune: clasele din care fac parte copiii cu numerele x și y se reunesc. Dacă x și y fac deja parte din aceeași clasă, operația nu se efectuează


  • 2 x y – întrebare: copiii cu numerele x și y sunt sau nu în aceeași clasă?

Cerinţa[edit | edit source]

Răspundeți la toate întrebările de al doilea tip, în ordinea acestora.

Date de intrare[edit | edit source]

Programul citește de la tastatură numerele N și M, iar apoi M triplete de numere naturale de forma op x y, unde op poate lua doar valorile 1 și 2, aceste triplete reprezentând câte o operație.

Date de ieşire[edit | edit source]

Programul va afișa pe ecran, pe câte o linie, răspunsul la fiecare întrebare de tip 2. Dacă la întrebarea 2 x y răspunsul este afirmativ, adică x și y se află în aceeași clasă, atunci veți afișa DA, iar în caz contrar veți afișa NU.

Restricții și precizări[edit | edit source]

  • 1 ≤ N ≤ 500
  • 2 ≤ M ≤ 2000
  • va exista cel puțin o operație de tip 1 și cel puțin o operație de tip 2.

Exemplul 1[edit | edit source]

Intrare
6 6
1 1 4
1 3 6
2 4 6
1 1 3
2 4 6
2 1 6
Ieșire
Datele introduse corespund restricțiilor impuse.
NU
DA
DA

Exemplul 2[edit | edit source]

Intrare
6 6
1 1 4
1 3 6
2 4 6
1 1 3
2 4 6
2 1 520
Ieșire
Datele introduse nu corespund restricțiilor impuse.

Explicație[edit | edit source]

Sunt 6 copii și 6 operații. După primele două operații, elevii 1 și 4 sunt în aceeași clasă și 3 și 6 sunt în aceeași clasă. La întrebarea 2 4 6 răspunsul este evident NU. La a patra operație 1 și 3 sunt trecuți în aceeași clasă, deci va exista o clasă cu 4 copii: {1,3,4,6}, deci la ultimele două întrebări acum răspunsul este DA la ambele.

Rezolvare[edit | edit source]

<syntaxhighlight lang="python" line>

  1. 3338 - disjoint

def validare(n, m, operati):

   # Verificăm dacă N și M sunt în limitele specificate și dacă avem numărul corect de operații
   if n < 1 or n > 500 or m < 2 or m > 2000 or len(operati) != m:
       raise ValueError
   tip1 = tip2 = False
   for op, x, y in operati:
       # Verificăm dacă există cel puțin o operație de fiecare tip
       if op == 1:
           tip1 = True
       elif op == 2:
           tip2 = True
       # Verificăm dacă operațiile sunt valide
       if op not in [1, 2] or x < 1 or x > n or y < 1 or y > n:
           raise ValueError
   # Verificăm dacă există cel puțin o operație de fiecare tip
   if not (tip1 and tip2):
       raise ValueError
   print("Datele de intrare corespund restrictiilor impuse")
   return True


  1. Funcția 'rezolvare' rezolvă problema dată

def rezolvare(n, _, operati):

   # Inițializăm părinții și rangurile
   parent = [i for i in range(n + 1)]
   rank = [0 for _ in range(n + 1)]
   res = []
   # Funcția 'find' găsește reprezentantul unui element
   def find(i):
       if parent[i] == i:
           return i
       return find(parent[i])
   # Funcția 'union' unește două seturi
   def union(x1, y2):
       xroot = find(x1)
       yroot = find(y2)
       # Atașăm arborele mai mic la rădăcina celui mai mare
       if rank[xroot] < rank[yroot]:
           parent[xroot] = yroot
       elif rank[xroot] > rank[yroot]:
           parent[yroot] = xroot
       else:
           parent[yroot] = xroot
           rank[xroot] += 1
   # Parcurgem operațiile și le aplicăm
   for op, x, y in operati:
       if op == 1:
           union(x, y)
       else:
           # Dacă x și y au același părinte, atunci sunt în aceeași clasă
           if find(x) == find(y):
               res.append('DA')
           else:
               res.append('NU')
   # Afișăm rezultatele
   print('\n'.join(res))


  1. Acest cod va fi executat doar dacă scriptul este rulat direct

if __name__ == '__main__':

   try:
       # Citim datele de intrare
       N, M = map(int, input().strip().split())
       operatii = [list(map(int, input().strip().split())) for _ in range(M)]
       # Validăm datele de intrare
       validare(N, M, operatii)
       # Rezolvăm problema
       rezolvare(N, M, operatii)
   # Tratăm eventualele erori
   except ValueError:
       print("Datele de intrare nu corespund restrictiilor impuse")

</syntaxhighlight>