Задача коммивояжёра с возвратом в "магазин" - Prolog
Формулировка задачи:
Вроде и тема раскрытая (код можно найти, для этой задачи), но что-то я застрял на
По условию задачи продавец развозит топливо по городам. Если у него топливо закончилось - ему надо возвратиться в магазин (store). Города пройти по одному разу. Нашёл код, добавил обработку значений для запаса топлива продавца: если=0, то сразу в город; если меньше необходимого городу то уменьшаем данные у города, и оправляем продавца в магазин, если больше, уменьшаем запасы продавца и идём в следующий город.
За одно и путь считаю.
Листинг программы
- retract(oil(To,Y)),
Листинг программы
- :- dynamic way/3.
- :- dynamic way/2.
- :- dynamic oil/2.
- :- dynamic capacity/1.
- % ***************************************************************************
- % Distance between trees.
- way(town,town2,50).
- way(town3,town4,50).
- way(town5,town4,35).
- way(town2,town6,55).
- way(town5,town6,35).
- way(town,town7,40).
- way(town7,town3,35).
- % Distance between the well and the trees.
- way(town,13).
- way(town2,19).
- way(town3,22).
- way(town4,34).
- way(town5,19).
- way(town6,22).
- way(town7,34).
- %
- oil(town,3).
- oil(town2,9).
- oil(town3,2).
- oil(town4,4).
- oil(town5,9).
- oil(town6,2).
- oil(town7,4).
- % Bucket capacity.
- capacity(5).
- % ***************************************************************************
- node(Node):-
- way(Node, _Destination,_);
- way(_Source, Node,_).
- % Определим предикат, возвращающий вершину – либо начало, либо конец дуги,
- % получим все вершины при помощи findall, а затем – преобразуем список во множество.
- get_nodes(SetOfNodes):-
- findall(Node, node(Node), Nodes),
- list_to_set(Nodes, SetOfNodes).
- % ***************************************************************************
- % Правило, проверяющее существование ребра (без учета направления):
- exist_edge(From, To, Lengh):-
- way(From, To, Lengh);
- way(To, From, Lengh).
- dfs(From, To, _, [From, To],_, _):-
- exist_edge(From, To, _).
- dfs(From, To, Buffer, [From|Path], AllLengh, Well):-
- exist_edge(From, X, Lengh),
- not(member(X, Buffer)),
- oil(X,Y),
- % первоначальный вариант, комивояжёр в городе без топлива
- (Well=0, capacity(NewWell),
- way(From,Z),
- % изменяем путь
- NewLenth is AllLengh + Z,
- % добавляем путь в магазин и из магазина
- dfs(X, To, [From|[store|Buffer]], Path, NewLenth, NewWell);
- % вариант, топлива хватит для потребностей города
- (Well>Y, NewLenth is AllLengh + Lengh,
- NewWell is (Well-Y),
- % идём дальше с остаткаим топлива
- dfs(X, To, [From|Buffer], Path, NewLenth, NewWell);
- % вариант, топлива не хватит для потребностей города
- Well<Y, way(From,Z), capacity(W),
- % изменяем путь
- NewLenth is AllLengh + Z,
- % новая потребность города
- NewWell is (Well-Y),
- % удаляю старое, необходимое ко-во топлива
- retract(oil(To,Y)),
- % добавляю новое, необходимое ко-во топлива
- assertz(oil(From, NewWell)),
- dfs(From, To, Buffer, [From|[store|Path]], Path, NewLenth, W))).
- hamiltonian_graph(Path, Well):-
- % получаем все вершины (в Nodes)
- get_nodes(Nodes),
- length(Nodes, NodesCount),
- % набираем топливо
- capacity(V),
- dfs(Node, Node, [store], Path, V, Well),
- list_to_set(Path, PathNodesSet),
- length(PathNodesSet, NodesCount), !.
Решение задачи: «Задача коммивояжёра с возвратом в "магазин"»
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]]).
- % **************************************************************
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д