0401 - Pachete Multe

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

Într-un depozit foarte mare există un raft cu n+1 spații de depozitare, numerotate de la 1 la n+1. Primele n spatii de depozitare sunt ocupate cu n pachete numerotate cu valori între 1 și n, iar spațiul de depozitare n+1 este gol.

Administratorul depozitului decide mutarea pachetelor, astfel încât pentru orice i, pachetul numerotat cu i să se afle în spațiul de depozitare i. Pentru aceasta se va folosi spațiul de depozitare suplimentar, n+1, singura manevră validă fiind mutarea unui pachet dintr-un spațiu de depozitare în altul, cu condiția ca acesta să fie gol.

Determinați o succesiune de manevre prin care fiecare pachet să fie în spațiul corect.

Date de intrare

Fişierul de intrare pachete_multeIN.txt conţine pe prima linie numărul n, iar pe a doua linie n numere naturale separate prin spaţii. Al i-lea număr reprezintă numărul pachetului aflat în spațiul de depozitare i.

Date de ieşire

Fişierul de ieşire pachete_multeOUT.txt va conţine pe prima linie numărul M, reprezentând numărul de manevre efectuate. Pe fiecare dintre următoarele M linii se descrie o manevră, prin două numere i j, cu semnificația: se ia pachetul din spațiul i și se mută în spațiul j. În cazul în care restricțiile nu sunt îndeplinite, se va afișa mesajul "Datele nu corespund restrictiilor impuse".

Restricţii şi precizări

  • 1 ≤ n ≤ 100000 <— ATENȚIE AICI
  • pentru fiecare manevră i j efectuată, 1 ≤ i,j ≤ n+1, i ≠ j, iar spațiul j trebuie să fie gol
  • numărul de manevre realizate nu trebuie să fie minim

Exemplul 1:

pachete_multeIN.txt

5
2 5 4 3 1 

pachete_multeOUt.txt

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

Exemplul 2:

pachete_multeIN.txt

100001
2 5 4 3 1 

pachete_multeOUt.txt

Datele nu corespund restrictiilor impuse

Rezolvare

def verifica_restricțiile(n, sol):
    if n < 1 or n > 100000:
        return False

    for i in range(1, n + 1):
        if sol[0][i] < 1 or sol[0][i] > n + 1 or sol[1][i] < 1 or sol[1][i] > n + 1 or sol[0][i] == sol[1][i]:
            return False

    return True


def main():
    INTRARE = "pachete_multeIN.txt"
    IESIRE = "pachete_multeOUT.txt"

    NMAX = 1000 * 100 + 1

    v = [0] * NMAX
    p = [0] * NMAX
    sol = [[0] * (NMAX * 2) for _ in range(2)]

    with open(INTRARE, 'r') as intrare, open(IESIRE, 'w') as iesire:
        n = int(intrare.readline())
        data = list(map(int, intrare.readline().split()))

        if len(data) != n:
            iesire.write("Datele nu corespund restrictiilor impuse\n")
            return

        for i in range(1, n + 1):
            v[i] = data[i - 1]
            p[data[i - 1]] = i

        p[0] = n + 1
        nr = 0
        for i in range(1, n + 1):
            if v[i] == i:
                continue

            if p[0] != i:
                nr += 1
                sol[0][nr] = i
                sol[1][nr] = p[0]
                v[p[0]] = v[i]
                p[v[i]] = p[0]
                v[i] = 0
                p[0] = i

            nr += 1
            sol[0][nr] = p[i]
            sol[1][nr] = i
            v[i] = i
            v[p[i]] = 0
            p[0] = p[i]
            p[i] = i

        if not verifica_restricțiile(n, sol):
            iesire.write("Datele nu corespund restrictiilor impuse\n")
            return

        iesire.write(str(nr) + '\n')
        for i in range(1, nr + 1):
            iesire.write(str(sol[0][i]) + ' ' + str(sol[1][i]) + '\n')

if __name__ == "__main__":
    main()