Персональные инструменты
 

Задача коммивояжера — различия между версиями

Материал из CustisWiki

Перейти к: навигация, поиск
м (реплицировано из внутренней CustisWiki)
м (Содержимое страницы заменено на «#REDIRECT [[discopal:{{PAGENAME}}]]»)
 
(не показано 5 промежуточных версий 3 участников)
Строка 1: Строка 1:
Задача коммивояжера (В англоязычной литературе — Traveling Salesman Problem, сокращенно TSP), заключается в следующем:
+
#REDIRECT [[discopal:{{PAGENAME}}]]
 
+
Заданы ''n'' городов <math>v_1,v_2,\ldots,v_n</math>
+
и попарные расстояния <math>d_{ij} \equiv d(v_i,v_j)</math> между ними,
+
являющиеся положительными целыми числами.
+
 
+
Чему равна наименьшая возможная длина кольцевого маршрута,
+
проходящего по одному разу через все города? Иными словами, требуется
+
найти минимально возможное значение суммы
+
<math>\sum_{i=1}^{n-1} d_{\pi(i),\pi(i+1)} +d_{\pi(n),\pi(1)}</math>,
+
где минимум берется по всем перестановкам <math>\pi(1),\ldots,\pi(n)</math> чисел
+
''1,…,n''.
+
 
+
Приведенный ниже пример переборного алгоритма и его выполнения, демонстрирует его неэффективность, и невозможность нахождения точного решения для данных реальных объемов:
+
 
+
<code-python>
+
# Находит и возвращает гамильтонов цикл минимального веса
+
# в графе G. Использует перебор по всем вершинам кроме первой.
+
def tsp_permutations(G):
+
    min_path_length=1e300  # устанавливаем минимальную длину в бесконечность
+
    min_path=[]
+
    start_node=G.nodes()[0] # Фиксируем начальный узел (сокращаем перебор).
+
    for path in xpermutations(G.nodes()[1:]): # перебор всех узлов кроме первого.
+
        path.insert(0,start_node)    # добавляем в начало пути стартовый узел
+
        path_length=0                # обнуляем длину текущего пути 
+
        path_is_ok=1                # Сначала считаем, что путь проходим
+
        for i in range(0,len(path)):
+
            v1=path[i]  #выбираем ребро (v1,v2), для текущей вершины
+
            if i<len(path)-1:     
+
                v2=path[i+1]
+
            else:
+
                v2=path[0]          # Если нода-последняя, то замыкаем путь.
+
 
+
            if G.has_edge(v1,v2):
+
                path_length=path_length+G.get_edge(v1,v2)       
+
            else: 
+
                path_is_ok=0  # нет ребра (v1,v2) - путь непроходим.
+
                break
+
        if (path_is_ok):
+
                print path, path_length
+
                if min_path_length>path_length:
+
                    min_path_length=path_length       
+
                    min_path=path       
+
    print "Optimal path:",min_path, min_path_length
+
    return min_path
+
</code-python>
+
 
+
['NY', 'Moscow', 'Minsk', 'Berlin', 'Kiev'] 205
+
['NY', 'Moscow', 'Minsk', 'Kiev', 'Berlin'] 170
+
['NY', 'Moscow', 'Berlin', 'Minsk', 'Kiev'] 225
+
['NY', 'Moscow', 'Kiev', 'Minsk', 'Berlin'] 155
+
['NY', 'Berlin', 'Moscow', 'Minsk', 'Kiev'] 210
+
['NY', 'Berlin', 'Minsk', 'Moscow', 'Kiev'] 175
+
['NY', 'Berlin', 'Minsk', 'Kiev', 'Moscow'] 155
+
['NY', 'Berlin', 'Kiev', 'Minsk', 'Moscow'] 170
+
['NY', 'Kiev', 'Moscow', 'Minsk', 'Berlin'] 175
+
['NY', 'Kiev', 'Minsk', 'Moscow', 'Berlin'] 210
+
['NY', 'Kiev', 'Minsk', 'Berlin', 'Moscow'] 225
+
['NY', 'Kiev', 'Berlin', 'Minsk', 'Moscow'] 205
+
Optimal path: ['NY', 'Moscow', 'Kiev', 'Minsk', 'Berlin'] 155
+
 
+
<graph>
+
graph G{ rankdir=LR;
+
NY -- Berlin[fontcolor="blue",label="$50",style="bold"];
+
NY -- Moscow[fontcolor="blue",label="$60",style="bold"];
+
NY -- Kiev[fontcolor="blue",label="$80",style="solid"];
+
Moscow -- Berlin[fontcolor="blue",label="$50",style="solid"];
+
Moscow -- Minsk[fontcolor="blue",label="$15",style="solid"];
+
Moscow -- Kiev[fontcolor="blue",label="$10",style="bold"];
+
Minsk -- Berlin[fontcolor="blue",label="$20",style="bold"];
+
Minsk -- Kiev[fontcolor="blue",label="$15",style="bold"];
+
Berlin -- Kiev[fontcolor="blue",label="$30",style="solid"];
+
}
+
</graph>
+
 
+
Конечно, разработаны различные методы сокращения перебора, кроме того, переборные задачи допускают эффективное распараллеливание на многопроцессорную технику или вычисление сетью обычных компьютеров (см. например, [http://www.tsp.gatech.edu/d15sol/ отчет]), но это не отменяет невозможности точного решения этой задачи, с ростом размера входных данных. Отсутствие же алгоритма субэкспоненциальной сложности для точного решения этой задачи следует из того, что эта задача является NP-полной, и общепринятой гипотезы о несовпадении классов '''P''' и '''NP'''.
+
 
+
Существуют различные алгоритмы для приближенного решения этой задачи или ее частных случаев.
+
 
+
==Метрическая задача коммивояжера==
+
 
+
Задача коммивояжера называется '''метрической''',
+
если для матрицы расстояний выполнено неравенство треугольника:
+
 
+
<math>
+
  \forall i,j,k \ \  d_{ik} \leq d_{ij} + d_{jk}
+
</math>
+
 
+
Для метрической задачи коммивояжера существует приближенный [[алгоритм Кристофидеса]].
+
 
+
[[Category:Задачи]]
+
{{replicate-from-custiswiki-to-lib}}
+

Текущая версия на 20:27, 13 июня 2011

  1. REDIRECT discopal:Задача коммивояжера