За последние 24 часа нас посетили 22774 программиста и 1263 робота. Сейчас ищут 765 программистов ...

Рассчет оптимального маршрута

Тема в разделе "Решения, алгоритмы", создана пользователем treez, 11 дек 2015.

  1. treez

    treez Новичок

    С нами с:
    11 дек 2015
    Сообщения:
    5
    Симпатии:
    0
    Доброго времени суток.
    На просторах интернета нашел такую вот задачку: Есть пункты, с расстояниями и временем пути между ними. Нужно при выборе двух точек отобразить расстояние и время. Если прямого соединения нету - нужно подобрать оптимальный маршрут (на этом и завис). Схематически это выглядит так:
    [​IMG]
    Таблица выглядит так (дамп здесь). Под список точек завел отдельную таблицу, айдишники которых ниже:
    Код (PHP):
    1. id    cities_id_1    cities_id_2    distance_km    time_mins
    2. 1    1    2    80    40
    3. 2    1    3    110    55
    4. 3    1    5    330    240
    5. 4    3    4    60    20
    6. 5    3    5    205    80
    7. 6    5    6    80    40
    8. 7    2    6    340    230
    9. 8    4    6    192    110
    Идея была такой: на вход подаю нужную точку, при помощи рекурсивной функции построить многомерный массив, который будет строиться, пока не будет достигнута конечная точка. В итоге получаю массив
    Код (PHP):
    1. $tree[1][3][4][6] 
    , который перебираю и получаю маршрут.

    На момент написания сего поста, функция виглядит так:
    Код (PHP):
    1. <?php
    2. $db = new PDO('mysql:host=localhost;dbname=task', 'root', '');
    3. $city_id = 1;
    4.  
    5. function getTree($id){
    6.     global $db;
    7.     $tree = array();
    8.     $query = "(SELECT cities_id_1 FROM distance_time WHERE cities_id_2=$id) UNION (SELECT cities_id_2 FROM distance_time WHERE cities_id_1=$id)";
    9.     $st = $db->query($query);
    10.     $res = $st->fetchAll(PDO::FETCH_ASSOC);
    11.     foreach($res as $k => $v){
    12.         if(is_array($v)){
    13.           foreach($v as $p){
    14.             $tree[$p] = getTree($p);
    15.             if($v == $p)
    16.                 continue;
    17.           }
    18.         }
    19.     }
    20.     return $tree;
    21. }
    22.  
    23. echo "<pre>";
    24. print_r(getTree($city_id));
    25. echo "</pre>";
    26.  
    27. ?>
    Чем я прошу Вас помочь:
    1. На верном ли я пути? Если есть другие пути решения, прошу подсказать какие, но так же прошу помочь в решении этим способом.
    2. С моей точки зрения пока функция написана верно, но страница падает, так и не загрузившись. Как заставить ЭТОТ код заставить сгенерировать хотя бы нужный мне массив. Пока не ставил запрос с объединением, а просто выбором с одного поля, все было нормально, работало как я и хотел.
    3. В случае получения нужного мне массива, я пока не представляю как использовать вложеность ключей, что бы их потом обработать и вывести нужный результат.

    ЗЫ. Я ОЧЕНЬ начинающий в этом деле, так что прошу сильно не ругать).

    PHP, JavaScript, SQL и другой код пишите внутри тегов
    Код ( (Unknown Language)):
    1. [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
     
  2. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    классическая задача комивояджера
     
  3. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.155
    Симпатии:
    1.769
    Адрес:
    :сердА
  4. treez

    treez Новичок

    С нами с:
    11 дек 2015
    Сообщения:
    5
    Симпатии:
    0
    За советы, конечно, спасибо, но хотелось бы услышать мнение специалистов. Что стобственно не так? Почему рекурсивная функция не работает так, как надо?
     
  5. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.155
    Симпатии:
    1.769
    Адрес:
    :сердА
    На вскидку:
    1) Тупо вычерпываешь лимит стека вызовов.
    2) Вычерпываешь лимит памяти.
    3) Вычерпываешь лимит времени.
    4) Накосячил с выходом из рекурсии и вводимый граф скидывает твой код в вечность.

    В чем ты кодишь? Отладчик прицеплен? Пошагово можешь продебажить?
     
  6. treez

    treez Новичок

    С нами с:
    11 дек 2015
    Сообщения:
    5
    Симпатии:
    0
    Был приятно удивлен, когда прочел об этом алгоритме. Оказывется, я хоть и не был незнаком с ним, но так и спланировал логику приложения.

    Добавлено спустя 1 минуту 7 секунд:
    Дружище, я пока ОЧЕНЬ начинающий в этом деле. Если тебе не сложно, объясни пожалуйста на "пальцах". А я пока погуглю все то, что ты написал)
     
  7. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.230
    Симпатии:
    1.715
    Адрес:
    Молдова, г.Кишинёв
    treez отладка (debug) это просто спаситель, ты можешь проследить как работает каждая строчка кода и какие данные содержит.

    Вручную http://phpfaq.ru/debug
    Через IDE https://netbeans.org/kb/docs/php/debugging_ru.html + например open-server.ru
    Online IDE c9.io
     
  8. treez

    treez Новичок

    С нами с:
    11 дек 2015
    Сообщения:
    5
    Симпатии:
    0
    Есть опенсервер и phpDesigner.
     
  9. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.230
    Симпатии:
    1.715
    Адрес:
    Молдова, г.Кишинёв
    В open-server есть XDebug, подключайся к нему из NetBeans ссылку на инструкцию я дал выше.
     
  10. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.155
    Симпатии:
    1.769
    Адрес:
    :сердА
    Окай.
    Стек - это такой накопитель, суть которого в том, что элемент, который был последним туда помещен, должен быть первым оттуда изъят. Как стопка тарелок. Кладем одну на одну и, в момент времени, у нас доступна только верхняя. Это называется LIFO - Last In, First Out.

    Когда ты вызываешь какую-то функцию, ты передаешь управление из одного кода в другой. А потом возвращаешь его обратно. Программе как-то надо отслеживать все эти прыжки и переходы, верно? И есть у нее такая вещь, как "стек вызовов".

    Это такой системный стек, куда складываются все вызовы функций в твоем коде. Когда ты вызываешь функцию, туда кладется запись. Когда функция завершается, самая последняя запись изымается, управление передается коду, который связан с записью, которая лежала под ныне изъятой. Вызвал ты функцию А из функции Б из функции В, получил стопочку из трех тарелочек (в каждой тарелочке, между прочим лежит в заблокированном состоянии вся занятая ранее память, запомни этот момент). В отработала, управление вернулось в тарелочку Б. Б отработала, управление вернулось в тарелочку А.

    Беда в том, что максимальная высота этой стопки тарелок не неограниченная. Потолок, в который она упирается, таки существует.
    Суть рекурсии в том, что ты, за N проходов складываешь в стопку N тарелок. Если это N ниже, чем наш потолок, то, в конце, все тарелочки будут убраны в обратном порядке. Если N выше, чем наш потолок - упс...


    Помнишь, я говорил, о том, что тарелочки не пустые? Дело в том, что количество памяти, которое разрешено скушать PHP за одну отработку ограничено. Оно правится в конфигах, разумеется, но ограничено. И по умолчанию не велико. Если твои тарелочки довольно увесисты, скрипт может попросту упереться в это ограничение и умереть - стол не выдержал стопку.


    Аналогично проблеме с памятью. В конфигах указано время, которое отводится на обработку запроса. Когда оно заканчивается, работа скрипта обрывается, закончил он ее или нет. Не успел сложить и разобрать тарелочки вовремя - твои проблемы.


    А это самое веселое - ты сказал, как надо складывать тарелочки, но не объяснил точно, когда надо прекратить этот процесс. То есть, если в предыдущих случаях процесс складывания конечен, но долог или ресурсоемок, в данном же варианте не помогут правки конфига. Править надо сам алгоритм.


    От себя еще добавлю, что
    1) Включи вывод ошибок.
    2) Найди, где у тебя лежат логи пхп и почитай их, мб чего интересного найдешь.
    3) Прислушайся к Денису по части отладки.
     
  11. treez

    treez Новичок

    С нами с:
    11 дек 2015
    Сообщения:
    5
    Симпатии:
    0
    Спасибо, друг. Пока буду все это переваривать и скоро вернусь с новыми вопросами)