0401 - Pachete Multe

De la Universitas MediaWiki

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()