Cod sursa(job #3333719)

Utilizator razvanfintaRazvan Fintaneanu razvanfinta Data 14 ianuarie 2026 22:36:20
Problema ADN Scor 0
Compilator py Status done
Runda Arhiva de probleme Marime 3.67 kb
def rezolva():
    # citesc datele de intrare din fisier
    with open("adn.in", "r") as f:
        n = int(f.readline().strip())
        secvente = []
        for i in range(n):
            secvente.append(f.readline().strip())
    
    # elimin secventele care sunt subsiruri ale altor secvente
    secvente_filtrate = []
    for i in range(n):
        este_subsir = False
        for j in range(n):
            if i != j and secvente[i] in secvente[j]:
                este_subsir = True
                break
        if not este_subsir:
            secvente_filtrate.append(secvente[i])
    
    secvente = secvente_filtrate
    n = len(secvente)
    
    # caz special: o singura secventa
    if n == 1:
        with open("adn.out", "w") as f:
            f.write(secvente[0] + "\n")
        return
    
    # calculez suprapunerea intre fiecare pereche de secvente
    # suprapunere[i][j] = cate caractere din sfarsitul lui i se suprapun cu inceputul lui j
    suprapunere = []
    for i in range(n):
        suprapunere.append([0] * n)
    
    for i in range(n):
        for j in range(n):
            if i == j:
                continue
            # caut cea mai mare suprapunere intre sfarsitul lui secvente[i] si inceputul lui secvente[j]
            lung_max = min(len(secvente[i]), len(secvente[j]))
            for k in range(lung_max, 0, -1):
                if secvente[i][-k:] == secvente[j][:k]:
                    suprapunere[i][j] = k
                    break
    
    # programare dinamica pe masca de biti
    # dp[masca][i] = lungimea minima a sirului care contine toate secventele din masca si se termina cu secventa i
    inf = float('inf')
    dp = []
    parinte = []  # pentru reconstructie: parinte[masca][i] = (masca_anterioara, j) - am ajuns de la j la i
    
    for masca in range(1 << n):
        dp.append([inf] * n)
        parinte.append([(-1, -1)] * n)
    
    # initializez: fiecare secventa singura
    for i in range(n):
        dp[1 << i][i] = len(secvente[i])
    
    # completez dp
    for masca in range(1, 1 << n):
        for ultim in range(n):
            if not (masca & (1 << ultim)):
                continue
            if dp[masca][ultim] == inf:
                continue
            
            # incerc sa adaug o noua secventa
            for urmator in range(n):
                if masca & (1 << urmator):
                    continue
                
                masca_noua = masca | (1 << urmator)
                cost_nou = dp[masca][ultim] + len(secvente[urmator]) - suprapunere[ultim][urmator]
                
                if cost_nou < dp[masca_noua][urmator]:
                    dp[masca_noua][urmator] = cost_nou
                    parinte[masca_noua][urmator] = (masca, ultim)
    
    # gasesc secventa finala cu lungime minima
    masca_finala = (1 << n) - 1
    lungime_min = inf
    ultim_optim = -1
    
    for i in range(n):
        if dp[masca_finala][i] < lungime_min:
            lungime_min = dp[masca_finala][i]
            ultim_optim = i
    
    # reconstruiesc ordinea secventelor
    ordine = []
    masca = masca_finala
    curent = ultim_optim
    
    while curent != -1:
        ordine.append(curent)
        masca_ant, ant = parinte[masca][curent]
        masca = masca_ant
        curent = ant
    
    ordine.reverse()
    
    # construiesc sirul final
    rezultat = secvente[ordine[0]]
    for i in range(1, len(ordine)):
        idx_ant = ordine[i - 1]
        idx_curent = ordine[i]
        # adaug doar partea care nu se suprapune
        suprap = suprapunere[idx_ant][idx_curent]
        rezultat += secvente[idx_curent][suprap:]
    
    # scriu rezultatul in fisier
    with open("adn.out", "w") as f:
        f.write(rezultat + "\n")


rezolva()