a[0],a[1]
# FUNCIONES
def sa(a, b, result): # result es un array que va acumulando los pasos dados. Ejemplo: result = ['pb','ra','sa','rra']
if len(a) > 1: a[0],a[1] = a[1],a[0]; result.append('sa')
return a, b, result
def sb(a, b, result):
if len(b) > 1: b[0],b[1] = b[1],b[0]; result.append('sb')
return a, b, result
def ss(a, b, result): # ss no llama a sa y sb ya que en result quedarían anotadas las tres funciones: ss, sa y sb
if len(a) > 1 or len(b) > 1:
result.append('ss')
if len(a) > 1: a[0],a[1] = a[1],a[0]
if len(b) > 1: b[0],b[1] = b[1],b[0]
return a, b, result
def pa(a, b, result):
if len(b) > 0:
a.insert(0, b[0])
b.pop(0); result.append('pa')
return a, b, result
def pb(a, b, result):
if len(a) > 0:
b.insert(0, a[0])
a.pop(0); result.append('pb')
return a, b, result
def ra(a, b, result):
if len(a) > 1: a.append(a.pop(0)); result.append('ra')
return a, b, result
def rb(a, b, result):
if len(b) > 1: b.append(b.pop(0)); result.append('rb')
return a, b, result
def rr(a, b, result):
if len(a) > 1 or len(b) > 1:
result.append('rr')
if len(a) > 1: a.append(a.pop(0))
if len(b) > 1: b.append(b.pop(0))
return a, b, result
def rra(a, b, result):
if len(a) > 1: a.insert(0, a.pop()); result.append('rra')
return a, b, result
def rrb(a, b, result):
if len(b) > 1: b.insert(0, b.pop()); result.append('rrb')
return a, b, result
def rrr(a, b, result):
if len(a) > 1 or len(b) > 1:
result.append('rrr')
if len(a) > 1: a.insert(0, a.pop())
if len(b) > 1: b.insert(0, b.pop())
return a, b, result
# PASOS NECESARIOS PARA COLOCAR CADA ELEMENTO DE A EN SU SITIO EN B total = pasosA + pasosB (esta suma es solo una idea, se ha de sumar de una forma peculiar)
def necesariosA(a, b): # array pasosA calcula los pasos necesarios para colocar cada elemento de A como el primero de su pila
for v in a:
if a.index(v) < len(a)/2:
pasosA.append(a.index(v))
else:
pasosA.append(-(len(a)- a.index(v)))
print("pila A:", a)
print("pila B:", b)
return pasosA
def necesariosB(a, b): # código nuevo: buscando el hueco
arr_target = [None] * len(a)
for i in range(len(a)):
if a[i] < min(b) or a[i] > max(b):
target = max(b); arr_target[i] = target
else:
for j in range(len(b)-1):
if a[i] < b[j] and a[i] > b[j+1]:
target = b[j+1]; arr_target[i] = target
elif a[i] < b[-1] and a[i] > b[0]:
target = b[0]; arr_target[i] = target
# en este momento ya tenermos el target completamente calculado
# ahora toca calcular pasosB
if b.index(target) < len(b)/2:
pasosB.append(b.index(target))
else:
pasosB.append(-(len(b)- b.index(target)))
return pasosB, arr_target
def totaliza(a, b): # totalizar pasos
global total
for i in range(len(pasosA)):
if pasosA[i] * pasosB[i] < 0: # si son de distinto signo, uno positivo y otro negativo
total.append(abs(pasosA[i]) + abs(pasosB[i])) # no hay sinergia
else: # si son de igual signo o alguno cero
total.append(max(abs(pasosA[i]), abs(pasosB[i]))) # si son de igual signo hay sinergia
return total
def calculaIndexPasosMinimos():
global pasosA, pasosB, total
pasosA = [] # [0,1,2, ...,41,-41,... , -2,-1] vector donde cada index está asociado con el valor del mismo index en A
pasosB = [] # [-3,2,-5, ..., -5,0] estos dos arrays se han de recalcular cada vez que realmente se mueva algún elemento de A a B
total = []
pasosA = necesariosA(a, b)
pasosoB, arr_target = necesariosB(a, b)
total = totaliza(a, b)
print("target:", arr_target)
print("pasosA:", pasosA)
print("pasosB:", pasosB)
print("total: ", total)
print()
return total.index(min(total)) # retorna el índice del elemento de la pila A que menos pasos totales necesita
def giraA(a, b, steps, result):
for i in range(abs(steps)):
if steps > 0:
ra(a, b, result)
elif steps < 0:
rra(a, b, result)
def giraB(a, b, steps, result):
for i in range(abs(steps)):
if steps > 0:
rb(a, b, result)
elif steps < 0:
rrb(a, b, result)
# girando pilas A y B
def giraPilas(a, b, indice, result): # indice es el index del valor en la pila A que deseamos poner el primero
if pasosA[indice] * pasosB[indice] > 0: # Existe sinergia, nos podemos ahorrar pasos. Estoy en el caso de que pasosA y pasosB tienen el mimso signo
pasos_comunes = min(abs(pasosA[indice]), abs(pasosB[indice]))
for i in range(pasos_comunes):
if pasosA[indice] > 0: # si el signo de ambos es positivo, ya que ambos tienen el mismo signo
rr(a, b, result)
elif pasosA[indice] < 0: # si el signo de ambos es negativo
rrr(a, b, result)
exceso_pasosA = abs(pasosA[indice]) - pasos_comunes
exceso_pasosB = abs(pasosB[indice]) - pasos_comunes
giraA(a, b, ((pasosA[indice] > 0) - (pasosA[indice] < 0)) * exceso_pasosA, result) # (a > 0) - (a < 0) da el signo de a
giraB(a, b, ((pasosB[indice] > 0) - (pasosB[indice] < 0)) * exceso_pasosB, result) # Python no tiene función sign
else: # No existe sinergia
giraA(a ,b, pasosA[indice], result) # gira A
giraB(a, b, pasosB[indice], result) # gira B
def situarMax_en_B(a, b, result): # situa el valor máximo de B en la primera posición de B
indice = b.index(max(b))
if indice < len(a)/2:
steps = indice
else:
steps = -(len(b)- indice)
giraB(a, b, steps, result)
def crecientesA(a, b, result): # situa los tres valores de A en forma creciente estricta: Ejemplo: 17, 45, 82
if a[0] < a[1] > a[2] and a[0] < a[2]: # caso: 1 3 2
ra(a, b, result)
sa(a, b, result)
rra(a, b, result)
elif a[0] > a[1] < a[2] and a[0] < a[2]: # caso: 2 1 3
sa(a, b, result)
elif a[0] < a[1] > a[2] and a[0] > a[2]: # caso: 2 3 1
rra(a, b, result)
elif a[0] > a[1] < a[2] and a[0] > a[2]: # caso: 3 1 2
ra(a, b, result)
elif a[0] > a[1] > a[2]: # caso: 3 2 1
sa(a, b, result)
rra(a, b, result)
return # caso: 1 2 3 en este caso no se hace nada pq ya están ordenados
# Después de ordenar los tres elementos de A en orden creciente estricto con la función crecientesA
def cremallera(a, b, result): # función que va pasando los números de B a A en forma de cremallera, intercalándolos con los que ya hay en A
aux = [a[-3], a[-2], a[-1]] # creamos un array aux con los tres últimos valores de A
while len(aux) > 0: # Mientras aux tenga elementos
maximo = max(b + aux) # calcula el maximo entre b y aux
if maximo in b: # si el maximo está en B hacer pa
pa(a, b, result)
print("pila A:", a)
print("pila B:", b)
print()
if maximo in aux: # si el máximo está en aux hacer rra y aux.pop
print("pila A:", a)
print("pila B:", b)
print()
rra(a, b, result)
aux.pop()
print("pila A:", a)
print("pila B:", b)
print()
while len(b) > 0: # ahora aux está vacío y solo queda hacer pa todo el rato
pa(a, b, result)
print("pila A:", a)
print("pila B:", b)
print()
if __name__ == "__main__":
from random import seed, shuffle
seed()
n = 20 # número de elementos de la pila
for muestra in range(1):
a = list(range(1, n+1)); shuffle(a) # generación aleatoria de la pila A
a = [2, 3, 6, 1, 4, 5]
a = [2, 4, 6, 1, 3, 5]
a = [3, 4, 5, 1, 2, 6]
a = [2, 3, 4, 1, 5, 6]
a = [3, 2, 6, 1, 4, 5]
a = [4, 3, 2, 1, 6, 5]
a = [4, 3, 2, 5, 6, 1]
b = []
a_original = a[:]
print("a_original:", a_original, "\n")
a_srt = ' '.join(map(str, a_original))
result = [] # recoje los pasos dados. Ejemplo: result = ['pb','ra','sa','rra']
pb(a, b, result); pb(a, b, result) # pasa de A a B la pareja de elementos de A elegidos a[0], a[1]
while len(a) > 3:
index_minimosPasos = calculaIndexPasosMinimos()
giraPilas(a, b, index_minimosPasos, result)
pb(a, b, result) # lo pasa de A a B haciendo pb
print("Ha finalizado el bucle while\n")
print("pila A:", a)
print("pila B:", b)
print()
situarMax_en_B(a, b, result) # situa el valor máximo de B en la primera posición de B
print("Situamos el máximo de B el primero\n")
print("pila A:", a)
print("pila B:", b)
print()
print("Odenamos A de forma creciente\n")
crecientesA(a, b, result) # situa los tres últimos valores de A en forma creciente estricta: Ejemplo: 17, 45, 82
print("pila A:", a)
print("pila B:", b)
print()
print("Ejecutamos el cremallera\n")
cremallera(a, b, result) # función que va pasando los números de B a A en forma de cremallera, intercalándolos con los que ya hay en A
print("pila A:", a)
print("pila B:", b)
print()
for i in range(len(result)-2):
if result[i]=='pb' and result[i+1]=='pa':
result.pop(i+1)
result.pop(i)
for i in range(len(result)-2):
if (result[i]=='rb' and result[i+1]=='ra') or (result[i]=='ra' and result[i+1]=='rb'):
result.pop(i+1)
result[i] = 'rr'
#print(len(result))
print(result)
largo = len(result)
#if largo <= 4900 or largo >= 5600:
print("a_original:", a_srt)
print(largo, a == sorted(a_original))
a_original: [4, 3, 2, 5, 6, 1] pila A: [2, 5, 6, 1] pila B: [3, 4] target: [4, 4, 4, 4] pasosA: [0, 1, -2, -1] pasosB: [-1, -1, -1, -1] total: [1, 2, 2, 1] Ha finalizado el bucle while pila A: [5, 6, 1] pila B: [2, 4, 3] Situamos el máximo de B el primero pila A: [5, 6, 1] pila B: [4, 3, 2] Odenamos A de forma creciente pila A: [1, 5, 6] pila B: [4, 3, 2] Ejecutamos el cremallera pila A: [1, 5, 6] pila B: [4, 3, 2] pila A: [6, 1, 5] pila B: [4, 3, 2] pila A: [6, 1, 5] pila B: [4, 3, 2] pila A: [5, 6, 1] pila B: [4, 3, 2] pila A: [4, 5, 6, 1] pila B: [3, 2] pila A: [3, 4, 5, 6, 1] pila B: [2] pila A: [2, 3, 4, 5, 6, 1] pila B: [] pila A: [2, 3, 4, 5, 6, 1] pila B: [] pila A: [1, 2, 3, 4, 5, 6] pila B: [] pila A: [1, 2, 3, 4, 5, 6] pila B: [] ['pb', 'pb', 'rrb', 'pb', 'rb', 'rra', 'rra', 'rra', 'pa', 'pa', 'pa', 'rra'] a_original: 4 3 2 5 6 1 12 True