Главная страница


ru.algorithms

 
 - RU.ALGORITHMS ----------------------------------------------------------------
 From : Rodion Gorkovenko                    2:5030/1286.6  05 Jun 2003  15:15:00
 To : Alex Rinas
 Subject : Алгоритм Дейкстры
 -------------------------------------------------------------------------------- 
 
 03 Jun 03 08:11, you wrote to All:
 
 AR>      Срочно нужна помошь в решении задачи по графам: Определение
 AR> кратчайшего маршрута движения автомобиля (>=7 вершин  >=10 дуг) указанным
 AR> алгоритмом на турбо-паскале.
 
 Я сразу оговорюсь - я в этом не разбираюсь совершенно, алгоритм Дейкстры уже
 забыл и на паскале писать не умею... Тем не менее, решил поднапрячься и вот, что
 у меня получилось. Точнее что получилось - смотри после подписи, а пока попробую
 объяснить.
 
 В целом алгоритм Дейстры - штука нехитрая. Его целью является поиск кратчайших
 путей из заданной вершины во все остальные (я так понимаю, это называется
 построением дерева кратчайших путей - а сам алгоритм это вариант поиска в ширину
 - правильно?) Идея в общем простая, как детский лепет.
 
 Пусть дан граф с N вершинами.
 
 Во-первых мы заводим массив размером N, в котором будем записывать текущие длины
 путей до соответствующих вершин.
 Пока что мы не нашли ни одного пути (путя?) и все эти длины равны, скажем,
 бесконечности (или, скажем, вообще не определены - неважно). Однако, подумав, мы
 можем догадаться, что путь в одну из вершин мы знаем точно - в ту вершину,
 откуда нужно начинать. Этот путь состоит ровным счетом из ничего и его длина
 равна 0.
 
 Все вершины кроме того удобно разбить на три группы
 1) те, до которых кратчайший путь уже найден
 2) те, до которых найден хоть какой-то путь
 3) те, до которых путь пока не найден
 Для обозначения принадлежности вершин к той или иной группе мы заведем еще
 массив флагов, имеющих три соответствующих состояния.
 
 Сначала все вершины, кроме стартовой, нужно будет отнести, разумеется, к третьей
 группе. Стартовую хорошо бы отнести к первой, но для инициализации алгоритма нам
 удобнее засунуть ее во вторую, сделав вид, что мы еще точно не знаем, кратчайший
 ли это путь. (который состоит из ничего и равен по длине 0)
 
 Теперь мы начинаем делать могучие шаги (итерации).
 
 Hа каждом шаге мы сначала просматриваем все вершины, которые находятся во 2
 группе (поэтому мы и засобачили сюда стартовую вершину) - вершины 1 группы нас
 уже не интересуют, а с вершинами 3 группы мы пока ничего не можем сделать. Из
 вершин второй группы мы выбираем ту, длина пути до которой минимальна. При этом 
 мы помним, что все пути из вершин 1 группы мы уже опробовали (см. дальше), а
 пути в остальные вершины 2 и 3 групп будут длиннее, чем теперешний путь до этой 
 минимальной. Поэтому мы можем быть твердо уверены, что к ней мы на этом шаге
 нашли кратчайший путь.
 
 Осталось понять, как же мы строим эти зловонные пути - пока про это ничего
 сказано не было. Строительство путей происходит на каждом шаге, после
 определения минимальной вершины. Мы просматриваем все вершины 2 и 3 группы, в
 которые есть ребро (дуга) из этой минимальной, то есть куда мы можем добраться
 следующим ходом. Если какая-то из этих вершин принадлежит 3 группе, мы радостно 
 осознаем, что мы нашли до нее путь (через текущую, минимальную вершину) и
 поэтому ее можно перевести во вторую группу. В таком случае мы переводим ее во
 вторую группу, а в массиве длин путей записываем, что добрались мы до нее по
 пути, состоящему из пути до текущей минимальной вершины (эту длину мы берем в
 этом же массиве) и ребра, соединяющего минимальную вершину с ней.
 Если же рассматриваемая вершина принадлежит ко 2 группе, значит мы уже находили 
 какой-то путь к ней (его длина уже записана в массиве длин) - и нам нужно
 определить, короче ли новый путь (из текущей минимальной вершины) чем старый
 (длина которого записана в массиве). Если он короче, то мы поступаем так же, как
 если бы эта вершина принадлежала к 3 группе.
 
 Вот, таким образом мы добавили еще одну вершину к 1 группе, и можем начинать
 следующий шаг алгоритма. Когда при поиске минимальной вершины будет выяснено,
 что все вершины находятся в 1 группе, работу можно считать законченной.
 
 В этом замечательном алгоритме (который я косноязычно описал) непонятно только
 одно - длины кратчайших путей мы получили - а как нам теперь восстановить сами
 пути - то есть порядок прохождения вершин на пути к конкретной какой-нибудь.
 
 Чтобы это можно было определить, нам изначально нужен еще один массив по
 количеству вершин (N), в котором мы будем хранить информацию о том, из какой
 вершины мы добрались в данную. Запись в этот массив производится тогда же, когда
 и запись в массив длин - мы записываем новую длину в один массив, а номер
 вершины, из которой мы добрались в текущую по пути с указанной длиной, в другой.
 Поскольку по ходу алгоритма значения из этого массива не используются, я его не 
 упомянул сразу, чтобы было проще (вот уж не знаю, стало ли действительно проще
 или нет).
 
 Реализация данного алгоритма вон там, после подписи. Программа запускается
 примерно так:
 DIJKSTRA.EXE <input.txt> <output.txt>
 
 Я привожу файл DIJKSTRA.PAS, из которого при компиляции должна бы получиться эта
 программа а также пример входного файла DIJKSTRA.TXT, который имеет следующий
 формат:
 N {количество вершин}
 S {номер стартовой вершины}
 From1 To1 Weight1 {тройка чисел, обозначающих ребра - из какой вершины оно}
 {выходит, в которую приходит и его вес - то есть его длина или там, сколько}
 {штрафов по проезду по нему придется заплатить}
 From2 To2 Weight2
 From3 To3 Weight3
 .... {и так далее}
 
 Прошу пардона, что так криво объяснил - у меня тут батарейка села в будильнике, 
 нужно идти покупать... Hу и еще масса причин, включая мою собственную кривость
 ;)
 
 Писал сам, только что (пятый паскаль достал ;) - работало, хотя глюки не
 исключены - самое тяжелое, если алгоритмические ;(
 
 с почтеньем,
 Rodion
 
 === Cut ===пошел файл DIJKSTRA.PAS
 {This text could be used anywhere in any possible or impossible way}
 {without any agreements or permissions from whoever could it be}
 
 {I am new to programming itself, to pascal and I do not know anything}
 {about of Dijkstra's algotirhms and any other, so you should use this}
 {text on your own risk and I am not in response to results of using it,}
 {regardless, which way of using it you kept}
 
 {Commetns, complains and curses of any kind could be addressed to anyone,}
 {including fidonet 2:5030/1286.6}
 
 {Excuse me for poor english - I forgot about installing keyrus this morning}
 
 {$A-,B-,D+,E-,F-,I+,L+,N+,O-,R-,S+,V-}
 {$M 16384,0,655360}
 
 program dijkstra;
 
 const
  MAX_VERTICES=128;{sqr(MAX_VERTICES)*sizeof(int) should be less than 32K}
  STATE_EVALUATED=0;{shortest path to this vertex is already found}
  STATE_PROCESSING=1;{some path to this vertex is already found}
  STATE_UNTOUCHED=2;{no path to this vertex is found yet}
  NO_VERTEX=-1;
  NO_EDGE=-1;
 
 type
  intVector=array[0..0] of integer;
  pInteger=^intVector;
  vertexInfo=record
   pathFrom:integer;
   currentPathLength:integer;
   currentState:integer;
  end;{vertexInfo}
  vertexInfoVector=array [0..0] of vertexInfo;
 
 var
  nVertices,matrixSize,startVertex:integer;
  matrix:^intVector;
  verticesInfo:^vertexInfoVector;
 
 function
 GetMatrix(vertexFrom,vertexTo:integer):integer;
 begin
  GetMatrix:=matrix^[vertexFrom*nVertices+vertexTo];
 end;{GetMatrix}
 
 procedure
 SetMatrix(vertexFrom,vertexTo,edgeWeight:integer);
 begin
  matrix^[vertexFrom*nVertices+vertexTo]:=edgeWeight;
 end;{SetMatrix}
 
 function
 Initialize:boolean;
 var
  inFile:text;
  i,vertexFrom,vertexTo,edgeWeight:integer;
 begin
  Initialize:=FALSE;
  if ParamCount<2 then
   Exit;
  {$I-}
  Assign(inFile,ParamStr(1));
  Reset(inFile);
  if IOresult<>0 then
   Exit;
  Read(inFile,nVertices,startVertex);
  if (IOresult<>0) or (nVertices<0) or (nVertices>=MAX_VERTICES) then
   Exit;
  matrixSize:=nVertices*nVertices*sizeof(integer);
  GetMem(matrix,matrixSize);
  for i:=(matrixSize div sizeof(integer))-1 downto 0 do
   matrix^[i]:=NO_EDGE;
  while not SeekEOF(inFile) do begin
   Read(inFile,vertexFrom,vertexTo,edgeWeight);
   if IOresult<>0 then
    Exit;
   SetMatrix(vertexFrom,vertexTo,edgeWeight);
  end;{while}
  close(inFile);
  {$I+}
  GetMem(verticesInfo,nVertices*sizeof(vertexInfo));
  for i:=nVertices-1 downto 0 do
   verticesInfo^[i].currentState:=STATE_UNTOUCHED;
  verticesInfo^[startVertex].currentState:=STATE_PROCESSING;
  verticesInfo^[startVertex].currentPathLength:=0;
  verticesInfo^[startVertex].pathFrom:=NO_VERTEX;
  Initialize:=TRUE;
 end;{Initialize}
 
 procedure
 DestroyAll;
 begin
  FreeMem(verticesInfo,nVertices*sizeof(vertexInfo));
  FreeMem(matrix,matrixSize);
 end;{DestroyAll}
 
 procedure
 Process;
 label
  newIteration,doneProcessing;
 var
  bestLength,bestVertex,currentLength,currentVertex:integer;
 begin
  {On each iteration shortest path to some particular vertex is found}
  newIteration:
  {Searching for vertex from set of vertices currently being processed,}
  {path to which is shortest for this time}
  bestVertex:=-1;
  for currentVertex:=nVertices-1 downto 0 do begin
   if verticesInfo^[currentVertex].currentState=STATE_PROCESSING then begin
    currentLength:=verticesInfo^[currentVertex].currentPathLength;
    if (bestVertex<0) or (currentLength<bestLength) then begin
     bestVertex:=currentVertex;
     bestLength:=currentLength;
    end;{if}
   end;{if}
  end;{for}
  {If nothing found, shortest paths to all vertices is evaluated already}
  if bestVertex<0 then
   goto doneProcessing;
  {If some vertex was found, current path to it is the shortest one}
  verticesInfo^[bestVertex].currentState:=STATE_EVALUATED;
  {Evaluating path lengths to vertices, which are connected to this}
  for currentVertex:=nVertices-1 downto 0 do begin
   currentLength:=GetMatrix(bestVertex,currentVertex);
   if (verticesInfo^[currentVertex].currentState<>STATE_EVALUATED) and
    (currentLength<>NO_EDGE) then begin
    currentLength:=currentLength+bestLength;
    if (verticesInfo^[currentVertex].currentPathLength>currentLength) or
     (verticesInfo^[currentVertex].currentState=STATE_UNTOUCHED) then begin
     verticesInfo^[currentVertex].currentState:=STATE_PROCESSING;
     verticesInfo^[currentVertex].currentPathLength:=currentLength;
     verticesInfo^[currentVertex].pathFrom:=bestVertex;
    end;{if}
   end;{if}
  end;{for}
  goto newIteration;
   doneProcessing:
 end;{Process}
 
 procedure
 WriteResults;
 var
  outFile:text;
  i,currentVertex,currentLength,currentDepth:integer;
  doWrite:boolean;
 begin
  {$I-}
  Assign(outFile,ParamStr(2));
  Rewrite(outFile);
  if IOresult<>0 then
   Exit;
  {$I+}
  currentVertex:=startVertex;
  currentDepth:=0;
  doWrite:=TRUE;
  repeat
   if doWrite then begin
    for i:=0 to currentDepth do
     write(outFile,' ');
    currentLength:=verticesInfo^[currentVertex].currentPathLength;
    writeln(outFile,'Vertex-',currentVertex,' by ',currentLength);
    doWrite:=FALSE;
   end;{if}
   i:=nVertices-1;
   while i>=0 do begin
    if verticesInfo^[i].pathFrom=currentVertex then begin
     currentVertex:=i;
     i:=-2;{Signal of special loop break condition}
     {if nothing found i would be equal to -1}
     currentDepth:=currentDepth+1;
     doWrite:=TRUE;
    end;{if}
    i:=i-1;
   end;{while}
   if i=-1 then begin
    i:=verticesInfo^[currentVertex].pathFrom;
    verticesInfo^[currentVertex].pathFrom:=NO_VERTEX;
    currentVertex:=i;
    currentDepth:=currentDepth-1;
   end;{if}
  until currentDepth<0;
  close(outFile);
 end;{WriteResults}
 
 begin
  if not Initialize then
   Halt(1);
  Process;
  WriteResults;
  DestroyAll;
 end.{main part}
 
 === Cut ===пошел файл DIJKSTRA.TXT
 6
 2
 0 4 1
 1 3 2
 1 5 1
 2 0 10
 2 1 5
 2 3 8
 3 4 4
 4 1 9
 4 3 1
 5 3 1
 5 4 6
 ===========все, больше ничего нет
 ---
  * Origin:  (2:5030/1286.6)
 
 

Вернуться к списку тем, сортированных по: возрастание даты  уменьшение даты  тема  автор 

 Тема:    Автор:    Дата:  
 Алгоритм Дейкстры help cрочно   Alex Rinas   03 Jun 2003 08:11:00 
 Алгоритм Дейкстры   Rodion Gorkovenko   05 Jun 2003 15:15:00 
Архивное /ru.algorithms/39753edf6992.html, оценка 3 из 5, голосов 10
Яндекс.Метрика
Valid HTML 4.01 Transitional