4290 - Gaseste Ciclu

De la Universitas MediaWiki
Versiunea pentru tipărire nu mai este suportată și poate avea erori de randare. Vă rugăm să vă actualizați bookmarkurile browserului și să folosiți funcția implicită de tipărire a browserului.

Cerinţa

Gigel are un graf cu n noduri și m muchii, care nu este conex. El dorește să afle răspunsul la două întrebări:

1) Care este numărul minim de muchii ce trebuie ađugate astfel încât graful să devină conex?

2) Dacă costul adăugării unei muchii între nodurile a și b este a + b, care este costul total minim al muchiilor care trebuie adăugate astfel încât graful să devină conex?

Date de intrare

Fișierul de intrare unirein.txt conține pe prima linie numerele n și m, pe a doua linie conține numărul c, reprezentând numărul cerinței 1 ⩽ c ⩽ 2, iar pe următoarele m linii se află muchiile grafului a b, 1 ⩽ a, b ⩽ n, a ≠ b.

Date de ieșire

Fișierul de ieșire unireout.txt va conține pe prima linie numărul S, reprezentând răspunsul cerut de Gigel.

Restricţii şi precizări

  • 1 ⩽ n ⩽ 100000, 0 ⩽ m ⩽ n-1
  • Pentru teste în valoare de 30 de puncte, cerința va fi 1.
  • Pentru teste în valoare de 40 de puncte, 1 ⩽ n ⩽ 1000.

Exemplul 1

unirein.txt
6 3
1
1 2
3 4
5 6
unireout.txt
Datele de intrare corespund restrictiilor impuse
2

Exemplul 2

unirein.txt
100001 1
1
1 2
unireout.txt
Datele de intrare nu corespund restrictiilor impuse

Rezolvare

import heapq


def find(parent, i):
    if parent[i] == i:
        return i
    return find(parent, parent[i])


def union(parent, rank, x, y):
    xroot = find(parent, x)
    yroot = find(parent, y)

    if rank[xroot] < rank[yroot]:
        parent[xroot] = yroot
    elif rank[xroot] > rank[yroot]:
        parent[yroot] = xroot
    else:
        parent[yroot] = xroot
        rank[xroot] += 1


def solve(n, c, edges):
    parent = [i for i in range(n+1)]
    rank = [0] * (n+1)

    for a, b in edges:
        union(parent, rank, a, b)

    sets = [find(parent, i) for i in range(1, n+1)]
    unique_sets = list(set(sets))

    if c == 1:
        return len(unique_sets) - 1
    else:
        costs = [i for i in unique_sets]
        heapq.heapify(costs)
        total_cost = 0

        while len(costs) > 1:
            cost1 = heapq.heappop(costs)
            cost2 = heapq.heappop(costs)
            total_cost += cost1 + cost2
            heapq.heappush(costs, cost1 + cost2)

        return total_cost


def main():
    with open('unirein.txt', 'r') as f:
        n, _ = map(int, f.readline().split())
        c = int(f.readline())
        edges = [list(map(int, line.split())) for line in f]

    if not (1 <= n <= 100000):
        print("Datele de intrare nu corespund restrictiilor impuse")
        return

    result = solve(n, c, edges)

    with open('unireout.txt', 'w') as f:
        f.write(str(result))

    print("Datele de intrare corespund restrictiilor impuse")


if __name__ == "__main__":
    main()

Explicaţie

Se vor uni nodurile 1 și 3, respectiv nodurile 1și 5, s-au folosit 2 muchii, iar costul total va fi 1 + 3 + 1 + 5 = 10.