Задача коммивояжёра с возвратом в "магазин" - 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]]).
 
% **************************************************************

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

15   голосов , оценка 4.2 из 5