Задача коммивояжёра с возвратом в "магазин" - Prolog
Формулировка задачи:
Вроде и тема раскрытая (код можно найти, для этой задачи), но что-то я застрял на
По условию задачи продавец развозит топливо по городам. Если у него топливо закончилось - ему надо возвратиться в магазин (store). Города пройти по одному разу. Нашёл код, добавил обработку значений для запаса топлива продавца: если=0, то сразу в город; если меньше необходимого городу то уменьшаем данные у города, и оправляем продавца в магазин, если больше, уменьшаем запасы продавца и идём в следующий город.
За одно и путь считаю.
Решение задачи: «Задача коммивояжёра с возвратом в "магазин"»
textual
Листинг программы
:- dynamic way/3.
:- dynamic way/2.
:- dynamic oil/2.
:- dynamic capacity/1.
% ***************************************************************************
% Distance between towns.
way(town1,town2,50).
way(town3,town4,50).
way(town5,town4,35).
way(town2,town6,55).
way(town5,town6,35).
way(town1,town7,40).
way(town7,town3,35).
% Distance between the well and the towns.
way(town1,13).
way(town2,19).
way(town3,22).
way(town4,34).
way(town5,19).
way(town6,22).
way(town7,34).
%
oil(town1,3).
oil(town2,9).
oil(town3,2).
oil(town4,4).
oil(town5,9).
oil(town6,2).
oil(town7,4).
% Bucket capacity.
capacity(5).
% ***************************************************************************
% учёт двунаправленности каждой дороги между городами
way_new(X,Y,Z):- way(X,Y,Z); way(Y,X,Z).
% учёт двунаправленности каждой дороги между городом и магазином
way_new(X,Y):- way(X,Y); way(Y,X).
% отновной предикат наждения пути робота
% Start - город, который уже обслужил коммивояжёр
% Way - список городов, путь коммивояжёра
% WayCost - длина этого пути
com_way(Start, Way, WayCost):-
% собираем список-множество всех городов
setof(X,Y^Z^way_new(X,Y,Z), Tree_set),
% находим любое соседний город (Finish)
way_new(Finish, Start, Cost),
% Удаляем Finish из множества городов
delete_first(Finish, Tree_set, Tree_set1),
capacity(V),
oil(Start,W),
get_oil(V, W, Start, 0, [well]),
write(V), write(' '), write(W), write(' '), writeln(Start),
% находим путь без циклов между Start и Finish, проходящий через все города
path_com(Finish, Start, Way1, WayCost1, Tree_set1),
% пересчитываем путь и его длину
WayCost is WayCost1 + Cost, Way=[Start|Way1].
% Вспомогательный предикат: удаление элемента списка
delete_first(X,[X|T],T):- !.
delete_first(X,[Y|T],[Y|TY]):- delete_first(X,T,TY).
% предикат поиска пути Way без циклов, длина пути WayCost, между городами Start и Finish,
% проходящий через все города из множества City_set
path_com(Start,Finish,Way,WayCost,City_set):-
path(Start,Finish,Way,WayCost,City_set,[Finish],0).
% базовый вспомогательный предикат поиска пути,
% предпоследние два аргумента - накапливающие параметры для пути и его стоимости
% когда все деревья уже посещены
path(Finish,Finish,Way,WayCost,[],Way,WayCost).
% иначе, идем путь из X в Finish через X
path(Finish,Finish,Way,WayCost,[],Way,WayCost).
% иначе, идем путь из X в Finish через X
path(X,Finish,Way,WayCost,City_set,PartWay,PartCost):-
% двигаемся к следующему дереву
way_new(X,Y,Cost), % есть дорога к дереву
member(Y,City_set), % Y ещё не посещён
% удаляем Y из множества непосещённых деревьев
delete_first(Y,City_set,City_set1),
% пересчёт длины пройденного пути
PartCost1 is PartCost+Cost,
% рекурсивно ищем путь из Y в Finish
path(Y,Finish,Way,WayCost,City_set1,[X|PartWay],PartCost1).
% предикат нахождения самого короткого пути
best_com_way(Start,Way):-
% находим все пути с их именами
findall(WayCost1/Way1,
com_way(Start,Way1,WayCost1), AllWays),
% находим минимальную длину пути
min_cost(AllWays,MinCost),
% выбор любого пути минимальной длины
member(MinCost/Way,AllWays).
% вспомогательный предикат вычисления минимальной длины пути:
% если путь один, то его длина минимальная,
% иначе выбор минимума из длины первого пути и длины минимального пути хвоста списка
min_cost([WayCost/_],WayCost):- !.
min_cost([WayCost1/_|Tail],MinCost):-
min_cost(Tail,MinCost1),
MinCost is min(WayCost1,MinCost1).
% **************************************************************
% get_oil(5,9, 'town5', 0, ['town5']).
get_oil(V, 0, Tree, Length, WellPath):- writeln('1'),!.
get_oil(V, W, Tree, Length, WellPath):- writeln('2'),
W<V,
V2 is V-W,
get_oil(V2, 0, Tree, Length, WellPath).
get_oil(V, W, Tree, Length, WellPath):- writeln('3'),
W>=V,
W2 is W-V,
capacity(V2),
way(Tree,L),
NewLength is Length+L*2,
get_oil(V2, W2, Tree, NewLength, [Tree|[well|WellPath]]).
% **************************************************************