1136 - Dragoni

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.

Enunț

Supărați că lansarea părții a treia a filmului lor preferat s-a amânat până în iunie 2018, Henry și Hetty s-au gândit la propriul scenariu pentru finalul trilogiei:

Într-o lume în care vikingii pot zbura cu dragonii există N insule. Hiccup, șeful tribului de vikingi aflat pe insula 1, știe M rute directe de zbor bidirecționale între insule. Pentru fiecare j intre 1 si M, ruta j unește insulele Aj și Bj și are lungime Dj.

Pe fiecare insulă i, (1 ≤ i ≤ n) există dragoni din specia i care pot zbura fără a se opri pentru odihnă o distanță maximă Dmaxi. Cu alte cuvinte, dragonii de pe insula i vor putea parcurge orice rută j, (1 ≤ j ≤ m) pentru care Dj ≤ Dmaxi, indiferent de ce alte drumuri au făcut anterior.

Hiccup dorește să ajungă de pe insula 1 pe insula N pentru a-l salva pe Toothless, dragonul lui. Pentru a ajunge acolo, el va lua inițial un dragon din specia 1 (de pe insula 1). Apoi, dacă la un moment dat Hiccup se află pe o insula i, (1 ≤ i ≤ n) având cu el un dragon din specia t, el poate:

  1. Să zboare de pe insula i pe o altă insulă x cu dragonul pe care îl are, folosind o rută directă j între insulele i si x, bineînțeles doar dacă Dj ≤ Dmaxt.
  2. Să schimbe dragonul din specia t pe care îl are cu un dragon din specia i aflat pe insula respectivă.

Cerințe

a. Să se determine distanța maxima Dmaxi caracteristică unui dragon la care Hiccup poate ajunge fără a schimba dragonul pe care l-a luat inițial de pe insula 1.

b. Să se determine distanța minimă pe care Hiccup trebuie să o parcurgă pentru a ajunge de pe insula 1 pe insula N.

Date de intrare

Fișierul de intrare dragoniIN.txt conține pe prima linie numărul p. Pentru toate testele de intrare, numărul p poate avea doar valoarea 1 sau valoarea 2. Pe a doua linie se găsesc două numere naturale N și M reprezentând numărul de insule, respectiv numărul de rute directe între insule. Pe a treia linie se găsesc N numere naturale, al i-lea dintre acestea reprezentând distanta maximă Dmaxi pe care o poate zbura un dragon de pe insula i. Pe următoarele M linii sunt descrise cele M rute directe. Pe fiecare dintre aceste linii se găsesc câte trei numere naturale A, B și D cu semnificația că există rută bidirecțională de lungime D între insulele A și B.

Date de ieșire

n fișierul de ieșire dragoniOUt.txt se va afișa un singur număr natural.

Dacă valoarea lui p este 1, se rezolvă numai cerința a.

În acest caz numărul afișat va reprezenta distanța maximă Dmaxi a unui dragon i la care Hiccup poate ajunge fără a schimba dragonul pe care l-a luat inițial de pe insula 1.

Daca valoarea lui p este 2, se va rezolva numai cerința b,

În acest caz numărul afișat va reprezenta distanța minima pe care Hiccup trebuie să o parcurgă pentru a ajunge de pe insula 1 pe insula N.Î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 ≤ 800
  • 1 ≤ M ≤ 6000
  • 1 ≤ Dmaxi ≤ 50 000, pentru orice 1 ≤ i ≤ N.
  • 1 ≤ Aj, Bj ≤ N, pentru orice 1 ≤ j ≤ M.
  • 1 ≤ Dj ≤ 50 000, pentru orice 1 ≤ j ≤ M.
  • Se garantează că Hiccup poate ajunge pe insula N.
  • Se garantează că răspunsul oricărei cerințe este un număr natural mai mic decât 109.
  • Pentru rezolvarea corectă a primei cerințe se acordă 20% din punctajul testului respectiv.
  • Pentru rezolvarea corectă a celei de-a doua cerințe se acordă 80% din punctajul testului respectiv.

Exemplul 1:

dragoniIN.txt

1
5 6
6 3 13 20 26
1 2 5
1 3 7
1 5 10
2 3 6
3 4 5
3 5 14

dragoniOUt.txt

20

Explicație

p = 1 deci se va rezolva cerința a).

Există N = 5 insule si M = 6 rute între ele. Hiccup pornește de pe insula 1 având un dragon care poate zbura o distanță de maxim 6. Cu acest dragon poate ajunge doar pe insulele 1, 2, 3 si 4, întrucât pentru a ajunge pe insula 5 el ar fi obligat sa parcurgă o ruta de lungime mai mare decât 6.

Distanta maxima pe care o poate zbura un dragon aflat pe insulele 1, 2, 3 sau 4 este deci 20 (dragonul de pe insula 4). Se observă că dragonul care poate zbura o distanță de 26 se afla pe insula 5 și este inaccesibil.

Exemplul 2:

dragoniIN.txt

1
801 6
6 3 13 20 26
1 2 5
1 3 7
1 5 10
2 3 6
3 4 5
3 5 14

dragoniOUt.txt

Datele nu corespund restrictiilor impuse

Rezolvare

import heapq

class Dij:
    def __init__(self, nod, cost):
        self.nod = nod
        self.cost = cost

    def __lt__(self, other):
        return self.cost > other.cost

def validate_restrictions(n, m, dmax):
    if not (1 <= n <= 800 and 1 <= m <= 6000):
        return False
    
    for i in range(1, n + 1):
        if not (1 <= dmax[i] <= 50000):
            return False
    
    return True

with open("dragoniIN.txt", "r") as fin, open("dragoniOUT.txt", "w") as fout:
    p = int(fin.readline())
    
    if p == 1:
        n, m = map(int, fin.readline().split())
        dmax = [0] + list(map(int, fin.readline().split()))

        if not validate_restrictions(n, m, dmax):
            fout.write("Datele nu corespund restrictiilor impuse\n")
            exit()

        gf = [[] for _ in range(n + 1)]

        for _ in range(m):
            a, b, c = map(int, fin.readline().split())
            if not (1 <= a <= n and 1 <= b <= n and 1 <= c <= 50000):
                fout.write("Datele nu corespund restrictiilor impuse\n")
                exit()
            gf[a].append((b, c))
            gf[b].append((a, c))

        q = []
        max_val = dmax[1]
        viz = [False] * (n + 1)
        viz[1] = True
        q.append(1)

        while q:
            nod = q.pop(0)

            for nex in gf[nod]:
                if nex[1] <= dmax[1] and not viz[nex[0]]:
                    viz[nex[0]] = True
                    max_val = max(max_val, dmax[nex[0]])
                    q.append(nex[0])

        fout.write(str(max_val) + "\n")

    elif p == 2:
        n, m = map(int, fin.readline().split())
        dmax = [0] + list(map(int, fin.readline().split()))

        if not validate_restrictions(n, m, dmax):
            fout.write("Datele nu corespund restrictiilor impuse\n")
            exit()

        cost = [[float('inf')] * (n + 1) for _ in range(n + 1)]
        costmin = [[float('inf')] * (n + 1) for _ in range(n + 1)]
        gf = [[] for _ in range(n + 1)]

        for _ in range(m):
            a, b, c = map(int, fin.readline().split())
            if not (1 <= a <= n and 1 <= b <= n and 1 <= c <= 50000):
                fout.write("Datele nu corespund restrictiilor impuse\n")
                exit()
            gf[a].append((b, c))
            gf[b].append((a, c))

        for i in range(1, n + 1):
            pq = []
            heapq.heappush(pq, Dij(i, 0))
            cost[i][i] = 0

            while pq:
                cur = heapq.heappop(pq)
                nod, costc = cur.nod, cur.cost

                if costc < cost[i][nod]:
                    continue

                for nex in gf[nod]:
                    if nex[1] <= dmax[i] and costc + nex[1] < cost[i][nex[0]]:
                        cost[i][nex[0]] = costc + nex[1]
                        heapq.heappush(pq, Dij(nex[0], cost[i][nex[0]]))

        class Stare:
            def __init__(self, nod, cost, dragon):
                self.nod = nod
                self.cost = cost
                self.dragon = dragon

        q = []
        q.append(Stare(1, 0, 1))
        costfinalmin = float('inf')
        costmin[1][1] = 0

        while q:
            cur = q.pop(0)
            nod, costc, dragon = cur.nod, cur.cost, cur.dragon

            if costc > costmin[dragon][nod]:
                continue

            for nex in gf[nod]:
                if nex[1] <= dmax[dragon]:
                    nexcost = costc + nex[1]
                    nexdrag = dragon
                    if dmax[nex[0]] > dmax[dragon]:
                        nexdrag = nex[0]
                    elif dmax[nex[0]] == dmax[dragon]:
                        nexdrag = min(dragon, nex[0])

                    if nexcost >= costmin[nexdrag][nex[0]]:
                        continue

                    costmin[nexdrag][nex[0]] = nexcost
                    q.append(Stare(nex[0], nexcost, nexdrag))

                    costfinalmin = min(costfinalmin, costmin[nexdrag][nex[0]] + cost[nexdrag][nex[0]])

        fout.write(str(costfinalmin) + "\n")