Вот подход, который генерирует случайные решения. Он перемещает все проверки переменных в цикл и замыкает цикл при столкновении:
import itertools, random
labels = list(range(16))
edges = ((0,1),(0,2),(0,3),(0,4),(0,5),(1,6),(2,7),(3,8),(4,9),(5,10),(6,11),(7,11),(8,11),(9,11),(10,11))
num_vertices = 12
def solve(labels,edges,num_vertices):
shuffled_labels = labels[:] #make a copy
random.shuffle(shuffled_labels)
for p in itertools.permutations(shuffled_labels,num_vertices):
differences = [0]*16
solved = True #innocent until proven guilty
for i,j in edges:
difference = abs(p[i]-p[j])
differences[difference] += 1
if differences[difference] == 2:
solved = False
break #no need to check more edges
if solved:
return p
Один прогон (около 1 минуты):
>>> solve(labels,edges,num_vertices)
(6, 5, 1, 14, 3, 2, 11, 15, 12, 13, 9, 0)
Это легко проверить, чтобы удовлетворить ваши ограничения.
Вот генераторное решение, которое даст все возможные решения:
def solutions(labels,edges,num_vertices):
for p in itertools.permutations(labels,num_vertices):
differences = [0]*16
solved = True #innocent until proven guilty
for i,j in edges:
difference = abs(p[i]-p[j])
differences[difference] += 1
if differences[difference] == 2:
solved = False
break #no need to check more edges
if solved:
yield p
Используется как, например ::
for p in solutions(labels,edges,num_vertices): print(p)
В отличие от случайного подхода, который обычно возвращается менее чем за минуту, генератор отрабатывает в течение очень долгого времени, прежде чем он начнет давать результаты. Это говорит о том, что перестановка тождеств (где начинается этот генератор) далека от решения. Тем не менее, он в конечном итоге приводит к перестановкам (примерно через 10-15 минут), первая из которых:
(0, 1, 3, 13, 14, 15, 10, 7, 6, 2, 4, 12)
(согласен с результатом @jasonharper).