3573 - Joc 11

De la Universitas MediaWiki

Enunt

Pentru un concurs de design de jocuri, Gigel vrea să construiască un joc. La joc participă n concurenţi numerotaţi de la 1 la n. Fiecare concurent are la dispoziţie câte un şir de m încăperi, numerotate de la 1 la m. Scopul jocului este de a găsi o comoară ascunsă în una din aceste încăperi. Fiecare încăpere conţine un cod, număr natural, fie egal cu 0, fie având cel puţin 2 cifre. Ultima cifră indică numărul de etape de penalizare, adică numărul de etape în care concurentul nu are voie să părăsească încăperea. Numărul obţinut prin eliminarea ultimei cifre a codului indică numărul încăperii în care se va deplasa acesta la următoarea etapă sau la expirarea penalizării.

Există două excepţii de la regula de definire a codului: numărul 9999 codifică o încăpere conţinând o comoară, iar numărul 0 o încăpere conţinând o capcana.

În etapa 1 fiecare jucător intră în încăperea 1 din şirul său de încăperi. În funcţie de codul găsit în încăpere sunt posibile următoarele situaţii:

  • codul găsit este 9999 ceea ce înseamnă că jucătorul este câştigător şi jocul se încheie la finalul acestei etape;
  • codul găsit este 0 ceea ce duce la eliminarea sa din joc;
  • pentru celelalte coduri, după efectuarea etapelor de penalizare, jucătorul efectuează o deplasare în încăperea indicată de cod. De exemplu la întâlnirea codul 157, după efectuarea celor 7 etape de penalizare jucătorul se va deplasa în camera 15.

Trecerea de la o etapă la alta se realizează simultan pentru toţi concurenţii.

Cerinţa

Fiind dat numărul n de concurenţi, numărul m de încăperi alocate fiecărui concurent, şi codurile din cele n×m încăperi să se determine câştigătorul jocului, numărul încăperii în care a găsit comoara, numărul de etape parcurse până când câştigătorul găseşte comoara precum şi numărul de concurenţi eliminaţi din joc până la etapa respectivă (inclusiv).

Date de intrare

Prima linie a fişierului de intrare joc11.in conţine două numere naturale n şi m, separate printr-un spaţiu, reprezentând numărul concurenţilor, respectiv numărul încăperilor. Următoarele n linii conţin câte m numere naturale, separate prin câte un spaţiu, reprezentând codurile din fiecare încăpere.

Date de ieșire

Prima linie a fişierului de ieşire joc11.out va conţine patru numere naturale separate prin câte un spaţiu, reprezentând indicele câştigătorului, numărul încăperii unde a găsit comoara, numărul etapei în care a câştigat şi respectiv numărul de concurenţi eliminaţi din joc.

Restricţii şi precizări

  • 1 ≤ n ≤ 400
  • 1 ≤ m ≤ 900
  • Pentru toate testele de intrare se garantează că există exact un câştigător.

Exemplu

joc11.in
4 8
0 9999 41 50 61 70 80 30
30 80 60 60 9999 21 40 50
20 30 40 50 61 71 81 9999
20 30 50 0 61 71 9999 41
joc11.out
2 5 7 1


Explicație

Câştigă jucătorul al 2-lea, după 7 etape, iar încăperea în care a găsit comoara este încăperea 5. În cele 7 etape a fost eliminat un singur concurent şi anume primul concurent. Încăperile prin care trece jucătorul câştigător până la final sunt: 1->3->6->2->8->5

Rezolvare

def simulate_game(n, m, rooms):
    winner = None
    room_number = None
    steps = 0
    eliminated = 0

    # Cream o listă de seturi pentru a memora concurenții eliminați în fiecare etapă
    eliminated_each_step = [set() for _ in range(m)]

    for step in range(m):
        next_rooms = [0] * n  # Inițializăm lista cu următoarele încăperi pentru fiecare concurent
        for i in range(n):
            if i in eliminated_each_step[step]:
                continue  # Dacă concurentul este deja eliminat în această etapă, nu facem nimic cu el

            code = rooms[i][step]  # Codul din încăperea curentă a concurentului

            if code == 9999:
                winner = i + 1
                room_number = step + 1
                steps = step + 1
                return winner, room_number, steps, eliminated

            if code == 0:
                eliminated += 1
                eliminated_each_step[step].add(i)
            else:
                next_room = int(str(code)[:-1])  # Obținem numărul următoarei încăperi
                next_rooms[next_room - 1] += 1

        # Actualizăm seturile de concurenți eliminați pentru etapele următoare
        for i in range(n):
            if next_rooms[i] > 1:
                eliminated_each_step[step + 1].add(i)

    return winner, room_number, steps, eliminated

def main():
    with open("joc11.in", "r") as fin:
        n, m = map(int, fin.readline().split())
        rooms = [list(map(int, fin.readline().split())) for _ in range(n)]

    winner, room_number, steps, eliminated = simulate_game(n, m, rooms)

    with open("joc11.out", "w") as fout:
        fout.write(f"{winner} {room_number} {steps} {eliminated}\n")

if __name__ == "__main__":
    main()