2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Помогите с задачкой на графы на С...
Сообщение25.11.2007, 23:26 


16/09/07
34
У предприятия существует большая сеть филиалов в разных
городах. Требуется написать программу, определяющую максимальное
время, требующееся курьеру для доставки секретного пакета из
одного произвольного филиала в другой произвольный филиал.
Известны координаты местонахождения филиалов и скорость
перемещения курьера.


Сначала была мысль сделать по алгоритму Дейкстры, только для максимального пути. Благо, нахождение минимального пути у меня есть и всё отлично работает, но...
Не вышло. Некоторое количество времени ушло на понимание того, что алгоритм Дейкстры неприменим к нахождению максимального пути, т.к. если на первом шаге выбирать минимальный путь из начальной вершины в какую-нибудь другую вершину, то можно эту вершину после этого шага вычеркнуть (в поиске минимального пути), а для максимальных путей это неверно, так ?

Возможно, можно сделать это как-то с помощью поиска в ширину или в глубину?

 Профиль  
                  
 
 Re: Помогите с задачкой на графы на С...
Сообщение26.11.2007, 01:21 
Заслуженный участник


15/05/05
3445
USA
Задача поставлена не совсем точно. Если в графе есть циклы, то максимальное время будет бесконечным.

 Профиль  
                  
 
 
Сообщение26.11.2007, 05:46 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Рискну предположить, что речь идёт о максимуме (по парам филиалов) минимального (по маршрутам) времени доставки.

 Профиль  
                  
 
 
Сообщение26.11.2007, 08:46 
Заслуженный участник


15/05/05
3445
USA
незваный гость писал(а):
:evil:
Рискну предположить, что речь идёт о максимуме (по парам филиалов) минимального (по маршрутам) времени доставки.
По крайней мере это имеет практическую интерпретацию.
По моему есть модификация волнового алгоритма для поиска всех минимальных путей из одного узла во все остальные. Тогда получается что-то вроде:
Код:
maxPath = 0;
for (i=0; i<n-1; i++)
{
    найти_все_минимальные_пути_из_узла( i );
    MaxT = максимальный_из_найденных_минимальных();
    if (MaxT > maxPath)
        maxPath = MaxT;
}

 Профиль  
                  
 
 
Сообщение26.11.2007, 09:05 


23/10/07
10
то есть нужно найти диаметр графа? Тогда это стандартная задача из учебника, решается через нахождение кратчайшего пути для каждой пары вершин.

 Профиль  
                  
 
 
Сообщение26.11.2007, 18:04 
Заслуженный участник


15/05/05
3445
USA
vasionok писал(а):
то есть нужно найти диаметр графа? Тогда это стандартная задача из учебника, решается через нахождение кратчайшего пути для каждой пары вершин.
Желательно бы избежать перебора всех пар. Алгоритм с поиском всех кратчайших путей из одной вершины должен быть немного эффективнее, чем (N-1)-кратное применение стандартного алгоритма Дейкстры.

 Профиль  
                  
 
 
Сообщение26.11.2007, 18:16 


23/10/07
10
Yuri Gendelman писал(а):
Желательно бы избежать перебора всех пар. Алгоритм с поиском всех кратчайших путей из одной вершины должен быть немного эффективнее, чем (N-1)-кратное применение стандартного алгоритма Дейкстры.


конечно же, пары не нужно перебирать явно. Однократное применение Дейкстры уже даёт кратчайшее растояние между (N-1)-й парой. Нужно применить Дейкстру для каждой вершины, взять максимальную из длин найденнных кратчайших путей. Или Уоршеллом-Флойдом тоже самое.

 Профиль  
                  
 
 
Сообщение26.11.2007, 18:49 
Заслуженный участник


15/05/05
3445
USA
vasionok писал(а):
Однократное применение Дейкстры уже даёт кратчайшее растояние между (N-1)-й парой.
Я собственно это и имел в виду. Просто при стандартной реализации для пары двух вершин алгоритм останавливается при достижении целевой вершины. А здесь нужно пройти весь граф и сохранить результаты для всех вершин.

Кроме того, я попытался сократить сложность, выкидывая, скажем, после 1-го шага 1-ю вершину, поскольку пары с ней на 2-м и последующих шагах уже не нужны. Но здесь я ошибся: выкидывать узлы нельзя. Можно не запоминать пути в 1-ю вершину, но это мало что дает, только усложняет алгоритм.
Алгоритм в моем первом посте исправлен.

 Профиль  
                  
 
 
Сообщение26.11.2007, 18:50 


16/09/07
34
Всем спасибо за советы. :)

Да, извиняюсь, забыл уточнить, что в графе нет циклов, каждую вершину можно посещать только один раз.

Вот код для нахождения минимальных путей по алгоритму Дейкстры:


Код:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>


#define TOPS 4



int v;
int main(int argc, char* argv[])
{

   

   int infinity=10000;                  
   int p = TOPS;                     
   int** a = LoadDataFromFile("data1.txt");


   int s = 1;            
   int g = 3;

    int x[TOPS]; //Массив, содержащий единицы и нули для каждой вершины,
                  // x[i]=0 - еще не найден кратчайший путь в i-ю вершину,
                  // x[i]=1 - кратчайший путь в i-ю вершину уже найден
   int t[TOPS];  //t[i] - длина кратчайшего пути от вершины s в i
   int h[TOPS];  //h[i] - вершина, предшествующая i-й вершине
                  // на кратчайшем пути

   // Инициализируем начальные значения массивов
   int u;          // Счетчик вершин
   for (u=0;u<p;u++)
   {
      t[u]=infinity; //Сначала все кратчайшие пути из s в i
   //равны бесконечности
      x[u]=0;        // и нет кратчайшего пути ни для одной вершины
   }
   h[s]=0; // s - начало пути, поэтому этой вершине ничего не предшествует
   t[s]=0; // Кратчайший путь из s в s равен 0
   x[s]=1; // Для вершины s найден кратчайший путь
   v=s;    // Делаем s текущей вершиной
   
   while(1)
   {
      // Перебираем все вершины, смежные v, и ищем для них кратчайший путь
      for(u=0;u<p;u++)
      {
         if(a[v][u]==0)continue; // Вершины u и v несмежные
         if(x[u]==0 && t[u]>t[v]+a[v][u]) //Если для вершины u еще не
   //найден кратчайший путь
               // и новый путь в u короче чем
   //старый, то
         {
            t[u]=t[v]+a[v][u];   //запоминаем более короткую длину пути в
   //массив t и
            h[u]=v;   //запоминаем, что v->u часть кратчайшего
   //пути из s->u
         }
       printf("%d\n",t[u]);
      }

      // Ищем из всех длин некратчайших путей самый короткий
      int w=infinity;  // Для поиска самого короткого пути
      v=-1;            // В конце поиска v - вершина, в которую будет
                       // найден новый кратчайший путь. Она станет
                       // текущей вершиной
      for(u=0;u<p;u++) // Перебираем все вершины.
      {
         if(x[u]==0 && t[u]<w) // Если для вершины u не найден кратчайший
                               // путь и если длина пути в вершину u меньше
                               // уже найденной, то
         {
            v=u; // текущей вершиной становится u-я вершина
            w=t[u];
         }
      }

      if(v==-1)
      {
        printf("No ways");
         break;
      }
      if(v==g) // Найден кратчайший путь,
      {        // выводим его
         printf("Min way = ");
         u=g;
         while(u!=s)
         {
            printf("%d<-",u);
            u=h[u];
         }
         printf("%d\n",s);
       printf("%d",t[g]);
         break;
      }
      x[v]=1;
   }
   free(a);
   return 0;
}



Здесь из файла считывается матрица смежности.


vasionok
Цитата:
Нужно применить Дейкстру для каждой вершины, взять максимальную из длин найденнных кратчайших путей.


Что-то с ходу не соображу, как тут это сделать, навскидку мысль поменять вот тут:

Код:
  int w=-10000; 
      v=-1;           
      for(u=0;u<p;u++)
      {
         if(x[u]==0 && t[u]>w)
                           
         {
            v=u;
            w=t[u];
         }
      }



, но это, вроде, не совсем правильно работает...

 Профиль  
                  
 
 
Сообщение05.12.2007, 10:36 


16/09/07
34
В общем, разобрался.
Оказалось всё очень просто, это я тупил. :) Просто применил алгоритм Дейкстры для всех вершин и нашёл из них максимум. Максимум из кратчайших путей.

Только вот такие вопросы...
Сложность алгоритма ведь зависит от того, как представлять граф: списком смежности или матрицей смежности? Верно ли, что в случае задания списком сложность будет O(V^2+E) (где V и E - кол-во вершин и рёбер соответственно), а в случае матрицы - O(n^2) (где n - кол-во вершин) ?

И ещё... задачу нахождения диаметра ведь можно решить поиском в ширину, но я не пробовал...
Так вот, если решать поиском в ширину, то какая получится сложность у алгоритма?
Саму-то по себе его сложность я знаю - O(V + E), но применительно к данной задаче... ?

 Профиль  
                  
 
 
Сообщение07.12.2007, 00:07 


31/08/07
5
Только вот такие вопросы...
Сложность алгоритма ведь зависит от того, как представлять граф: списком смежности или матрицей смежности? Верно ли, что в случае задания списком сложность будет O(V^2+E) (где V и E - кол-во вершин и рёбер соответственно), а в случае матрицы - O(n^2) (где n - кол-во вершин) ?

И ещё... задачу нахождения диаметра ведь можно решить поиском в ширину, но я не пробовал...
Так вот, если решать поиском в ширину, то какая получится сложность у алгоритма?
Саму-то по себе его сложность я знаю - O(V + E), но применительно к данной задаче... ?



Никогда не слыхал про упрощенный способ вычисления диаметра одним обходом в ширину. По некоторым соображениям это неправдоподобно. Есть более быстрые приближенные алгоритмы для длин всех путей но точных методов принципиально меньшей сложности чем Вы описали - нет. Так что придется запускать Дейкстру неконстантное число раз :(

Кстати у Вас вышло меньшее время чем должно быть. Дейкстра как мы знаем зависит 1) от реализации обхода графа и 2) от качества очереди реализующей (как минимум) decrease-key и extract-min. Обход графа реализуется за время O(E+V) в случае если граф представлен так что по любой вершине можно за константное время получить некий способ (указатель, итератор итп) позволяющий перечислить смежные с данной вершиной ребра. Таков например плюсовый BOOST Incidence Graph. Комбинируя с известным временем работы хорошей реализации нужного нам вида очереди, получаем общее время O(E + V * log V). Сколько там запусков - n-1? O(V*V log V + V*E) :(

Такое время никакая матрица не испортит :) Хотя естественно было б ожидать списка имеющихся путей между филиалами на входе, ведь у Вас же не полный граф там? Но по-любому если есть обход графа придется матрицу конвертировать во что-то более удобное, например в "инцидентный" вид - хотя бы потому сложность мы считали именно для такой реализации.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 11 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group