Skip to content
Snippets Groups Projects
Commit ad1d5af0 authored by Julien Courtiel's avatar Julien Courtiel
Browse files

solution of Ex1 - 2021

parent 06d228c5
No related branches found
No related tags found
No related merge requests found
### Pour les tests (à ne pas copier) ###
entree = """3
71
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 71 69 67 65 63 61 59 57 55 53 51 49 47 45 43 41 39 37 35 33 31 29 27 25 23 21 19 17 15 13 11 9 7 5 3 1
3
2 3 1
18
10 3 6 8 7 1 5 4 2 9 11 12 14 13 15 16 17 18
"""
import sys
from io import StringIO
sys.stdin = StringIO(entree)
### Définition d'une solution naïve ###
def cout_quadratique(tab):
"""Renvoie le coût de Reversort : autrement dit la somme des longueurs des bouts du tableau qui sont inversés.
Ceci implémante la solution attendue par le concours.
La complexité est quadratique."""
cout = 0
n = len(tab)
for i in range(n-1):
j = min(range(i,n) , key = lambda x : tab[x] )
cout += j - i + 1
#On procède à l'inversion de la sous-liste :
for k in range(0,(j-i)//2+1):
tab[i+k],tab[j-k] = tab[j-k],tab[i+k]
return cout
### Tentative d'une solution plus rapide ###
class ABR:
"""Cette première classe décrit des simples ABR qui déterminent dans quel intervalle les positions
successives de 2, 3, ... apparentiennent.
Une fois qu'on aura trouvé cet invervalle, on appliquera à la position de l'entier une succession
de transformations affines (cf classe suivante)"""
def __init__(self,x):
"""Initialise un noeud de l'ABR à x """
self.valeur = x
self.gauche = None
self.droit = None
def __repr__(self):
if self.gauche == None and self.droit == None:
return repr(self.valeur)
retour = '\n'
return f"|{repr(self.gauche).replace(retour,retour+'|')}\n{self.valeur}\n|{repr(self.droit).replace(retour,retour+'|')} "
class arbre_affine:
"""Cette classe décrit des arbres orientés des feuilles vers la racine.
Les feuilles correspondent à des intervalles dans lesquels la prochaine position peut appartenir.
On va remonter dans l'arbre et appliquer des transformations affines successives pour au final
obtenir la position de l'élément après renversements des sous-listes.
"""
def __init__(self):
"""Initialise un noeud de l'ABR à x """
self.parent = None
# Coefficients de la transformation x -> a*x + b
self.coeff = (1,0)
self.est_fils_gauche = True
def __repr__(self):
if self.parent == None:
return "racine"
conn = '-' if self.est_fils_gauche else '~'
return f"[{id(self) % 100//4}]{self.coeff} {conn}> {repr(self.parent)}"
def composition( X , Xp ):
a,b = X
ap,bp = Xp
return (a*ap,ap*b + bp)
def cout_via_ABR(tab):
"""Renvoie le coût de Reversort : autrement dit la somme des longueurs des bouts du tableau qui sont inversés.
La complexité est en O(N log(N))
"""
n = len(tab)
#pos va contenir les positions de chaque élément dans le tableau
pos = [ -1 ]*(n+1)
for i,x in enumerate(tab):
pos[x] = i
# Au départ
A = ABR(pos[1])
A.gauche = ABR(arbre_affine())
A.droit = ABR(arbre_affine())
racine = arbre_affine()
A.gauche.valeur.parent = racine
A.gauche.valeur.coeff = (-1,pos[1])
A.droit.valeur.parent = racine
A.droit.valeur.est_fils_gauche = False
cout = pos[1] + 1
#Traitement des nombres 1 par 1
for x in range(2,n):
#On commence par trouver l'intervalle dans lequel pos[i] appartient
p = pos[x]
tmp = A
while ( not( tmp.gauche == None and tmp.droit == None) ):
if p < tmp.valeur:
tmp = tmp.gauche
else:
tmp = tmp.droit
G = tmp.valeur
#On rajoute un nouveau noeud à l'ABR
tmp.valeur = p
tmp.gauche = ABR(G)
D = arbre_affine()
tmp.droit = ABR(D)
#On remonte à la racine de l'arbre affine
tmp = G
coeffg = (1,0)
coeffd = (1,0)
while( tmp.parent != None ) :
tc = tmp.coeff
if tc[0] == -1:
G,D = D,G
coeffg,coeffd = coeffd,coeffg
p = tc[0] * p + tc[1]
coeffg = composition(coeffg,tc)
coeffd = composition(coeffd,tc)
if tmp.est_fils_gauche:
D.est_fils_gauche = True
D.parent = tmp.parent
D.coeff = coeffd
coeffd = (1,0)
D = tmp.parent
else:
G.est_fils_gauche = False
G.parent = tmp.parent
G.coeff = coeffg
coeffg = (1,0)
G = tmp.parent
tmp = tmp.parent
#Normalement, si j'ai fait mon taf, G doit contenir des valeurs <p, et D > p
cout += p - x + 2
G.est_fils_gauche = True
D.est_fils_gauche = False
racine = arbre_affine()
G.parent = racine
D.parent = racine
G.coeff = composition(coeffg, (-1,p+x-1) )
D.coeff = coeffd
return cout
### BENCHMARK ###
import time
import matplotlib.pyplot as plt
def liste_aleatoire(longueur):
import random
L = [ i for i in range(1,longueur+1)]
random.shuffle(L)
return L
def test(liste_fonctions,n):
temps_execution = []
for fct in liste_fonctions:
#entree à changer ci-dessous :
entree = liste_aleatoire(n)
t = time.time()
fct(entree)
temps_execution.append(time.time()-t)
return temps_execution
def trace_courbes(liste_fonctions,debut,fin):
X = []
Y = [ [] for j in range(len(liste_fonctions)) ]
for i in range(debut,fin,max((fin-debut)//100,1)):
plt.clf()
X.append(i)
TE = test(liste_fonctions,i)
for j in range(len(TE)):
Y[j].append(TE[j])
plt.plot(X,Y[j])
plt.draw()
plt.pause(0.001)
### Traitement du problème ###
T = int(input())
for k in range(T):
n = int(input())
tableau = list(map(int,input().split(" ")))
print(f"Case #{k+1}: {cout_via_ABR(tableau)}")
# Google code jam solutions
En français :)
My code is commented in French, sorry for that :)
Voici pour l'instant ce qui a été réalisé :
Here what was done for now:
## 2021
* **Reversort:** Implementation of a solution in O(N log(N)) using BSTs. (It works!)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment