Комбинаторные алгоритмы для программистов

Алгоритмы на графах

Разбить на страницы
Показывать лекцию целиком

Поиск в глубину

При решении многих задач, касающихся ориентированных графов, необходим эффективный метод систематического обхода вершин и дуг орграфов. Таким методом является метод поиск в глубину. Метод поиска в глубину является основой многих эффективных алгоритмов работы с графами. Предположим, что есть ориентированный граф $$G$$, в котором первоначально все вершины помечены меткой " $$unvisited$$ ". Поиск в глубину начинается с выбора начальной вершины $$v$$ орграфа $$G$$, для этой вершины метка " $$unvisited$$ " меняется на метку " $$visited$$ ". Затем для каждой вершины, смежной с вершиной $$v$$ и не посещаемой раньше, рекурсивно применяется поиск в глубину. Когда все вершины, которых можно достичь из вершины $$v$$, будут рассмотрены, поиск заканчивается. Если некоторые вершины остались не посещенными, то выбирается одна из них и алгоритм повторяется. Этот процесс продолжается до тех пор, пока не будут обойдены все вершины орграфа $$G$$.

Метод получил свое название - поиск в глубину, поскольку поиск не посещенных вершин идет в направлении вглубь до тех пор, пока это возможно. Например, пусть $$x$$ является последней посещенной нами вершиной. Выбираем очередную дугу $$(x,y)$$ (ребро), выходящую из вершины $$x$$. Возможна следующая альтернатива: вершина $$y$$ помечена меткой " $$unvisited$$ "; вершина $$y$$ помечена меткой " $$visited$$ ". Если вершина $$y$$ уже посещалась, то отыскивается другая вершина, смежная с вершиной $$x$$ ; иначе вершина $$y$$ метится меткой " $$visited$$ " и поиск начинается заново от вершины $$y$$. Пройдя все пути, которые начинаются в вершине $$y$$, возвращаемся в вершину $$x$$, то есть в ту вершину, из которой впервые была достигнута вершина $$y$$. Затем процесс повторяется, то есть продолжается выбор нерассмотренных дуг, исходящих из вершины $$x$$, и так до тех пор, пока не будут исчерпаны все эти дуги.

Алгоритм Дейкстры нахождения кратчайшего пути

Рассмотрим алгоритм нахождения путей в ориентированном графе. Пусть есть ориентированный граф $$G(V,E)$$, у которого все дуги имеют неотрицательные метки (веса дуг), а одна вершина определена как источник. Задача состоит в нахождении весов кратчайших путей от источника ко всем другим вершинам граф $$G(V,E)$$. Здесь длина пути определяется как сумма весов дуг, составляющих путь. Эта задача часто называется задачей нахождения кратчайшего пути с одним источником. Отметим, что мы будем говорить о длине пути даже тогда, когда она измеряется в других, не линейных, единицах измерения, например, во временных единицах или в денежном эквиваленте.

Можно представить орграф $$G(V,E)$$ в виде карты маршрутов рейсовых полетов из одного города в другой. Каждая вершина соответствует городу, а ребро (дуга) $$(v,w)$$ - рейсовому маршруту из города $$v$$ в город $$w$$. Вес дуги $$(v,w)$$ - это время полета из города $$v$$ в город $$w$$. В этом случае решение задачи нахождения кратчайшего пути с одним источником для ориентированного графа трактуется как минимальное время перелета между различными городами.

Для решения поставленной задачи будем использовать "жадный" алгоритм, который называют алгоритмом Дейкстры (Dijkstra). Алгоритм строит множество $$S$$ вершин, для которых кратчайшие пути от источника уже известны. На каждом шаге к множеству $$S$$ добавляется та из оставшихся вершин, расстояние до которой от источника меньше, чем для других оставшихся вершин. Если веса всех дуг неотрицательны, то можно быть уверенным, что кратчайший путь от источника к конкретной вершине проходит только через вершины множество $$S$$. Назовем такой путь особым. На каждом шаге алгоритма используется также массив $$M$$, в который записываются длины кратчайших особых путей для каждой вершины. Когда множество $$S$$ будет содержать все вершины орграфа, то есть для всех вершин будут найдены особые пути, тогда массив $$M$$ будет содержать длины кратчайших путей от источника к каждой вершине.

Алгоритм Флойда нахождения кратчайших путей между парами вершин

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

Формулировка задачи.Есть ориентированный граф $$G(V,E)$$, каждой дуге (ребру) $$(v,w)$$ этого графа сопоставлен неотрицательный вес $$C_{vw}$$. Общая задача нахождения кратчайших путей заключается в нахождении для каждой упорядоченной пары вершин $$v,w$$ любого пути от вершины $$v$$ в вершину $$w$$, длина которого минимальна среди всех возможных путей от $$v$$ к $$w$$ .

Можно решать эту задачу, последовательно применяя алгоритм Дейкстры для каждой вершины, объявляемой в качестве источника. Но мы для решения поставленной задачи воспользуемся алгоритмом, предложенным Флойдом (R.W. Floyd). Пусть все вершины орграфа последовательно пронумерованы от 1 до $$n$$. Алгоритм Флойда использует матрицу $$A(n \times n)$$, в которой находятся длины кратчайших путей:

$$A_{ij} = C_{ij}$$, если $$i \ne j$$ ;

$$A_{ij} = 0$$, если $$i = j$$ ;

$$A_{ij} = \infty$$ если отсутствует путь из вершины $$i$$ в вершину $$j$$.

Над матрицей $$A$$ выполняется $$n$$ итераций. После $$k$$ -й итерации $$A_{ij}$$ содержит значение наименьшей длины пути из вершины $$i$$ в вершину $$j$$, причем путь не проходит через вершины с номерами большими $$k$$.

Вычисление на $$k$$ -ой итерации выполняется по формуле: $$A_{ij}^k = \min (A_{ij}^{k - 1},A_{ik}^{k - 1},A_{kj}^{k - 1} )$$ Верхний индекс $$k$$ обозначает значение матрицы $$A$$ после $$k$$ -ой итерации.

Для вычисления $$A_{ij}^k$$ проводится сравнение величины $$A_{ij}^{k -1}$$ (то есть стоимость пути от вершины $$i$$ к вершине $$j$$ без участия вершины $$k$$ или другой вершины с более высоким номером) с величиной $$A_{ik}^{k - 1} + A_{kj}^{k - 1}$$ (стоимость пути от вершины $$i$$ к вершине $$k$$ плюс стоимость пути от вершины $$k$$ до вершины $$j$$ ). Если путь через вершину $$k$$ дешевле, чем $$A_{ij}^{k - 1}$$, то величина $$A_{ij}^k$$ изменяется. Рассмотрим орграф:

(рис 16.1) Помеченный орграф

Матрица A(3 * 3) на нулевой итерации (k = 0)

$$\left[ {\begin{array}{*{20}c} 0 8 5 \\ 3 0 \infty \\ \infty 2 0 \\ \end{array} } \right]$$

Матрица A(3 * 3) после первой итерации (k = 1)

$$\left[ {\begin{array}{*{20}c} 0 8 5 \\ 3 0 8 \\ \infty 2 0 \\ \end{array} } \right]$$

Матрица A(3 * 3) после второй итерации (k = 2)

$$\left[ {\begin{array}{*{20}c} 0 8 5 \\ 3 0 8 \\ 5 2 0 \\ \end{array} } \right]$$

Матрица A(3 * 3) после третьей итерации (k = 3)

$$\left[ {\begin{array}{*{20}c} 0 7 5 \\ 3 0 8 \\ 5 2 0 \\ \end{array} } \right]$$

Программы

Программа 1. Построение матрицы инциндентности.

//Построение матрицы инциндентности
//Программа реализована на языке программирования Turbo-C++

\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <iostream.h>

struct elem
{
    int num;  /* Номер вершины */
    int suns; /* Количество сыновей */
    char str[20]; /* Строка с номерами сыновей */
    elem *next; /* Указатель на следующую вершину */
} *head, *w1, *w2;

int Connected(int i, int j)
{
    int k;
    char *str1;
    w2 = head;
    if(i == j) return 0;
    for(k=1; k<i; k++)
        w2 = w2->next;
    if( strchr(w2->str, j) ) return 1;
    return 0;
}

void main()
{

int tops;
    int i,j,k,l;
    char *str1;

clrscr();
    printf("Введите количество вершин  \n");
    scanf("%d", tops);

head = (elem *)malloc(sizeof(elem));
    head->num = 1;
    head->suns = 0;
    head->str[0] = '\0';
    head->next = NULL;

w1 = head;

for(i=2;i<=tops;i++)
    {
        w2 = (elem *)malloc(sizeof(elem));
        w2->num = i;
        w2->suns = 0;
        w2->str[0] = '\0';
        w2->next = NULL;

w1->next = w2;
        w1 = w2;
    }

w1 = head;

for(i=1; i<=tops; i++)
    {
//      clrscr();
        printf("Введите количество путей из вершины  %d\n", i);
        scanf("%d", k);

for(j=1; j<=k; j++)
        {
            printf("Введите связь %d\n", j);
            scanf("%d", l);
            if((l<=0) || (l > tops))
            {
                printf("Такой вершины нет, повторите попытку\n");
                l = 0;
                j--;
                continue;
            }
            w1->str[w1->suns++] = l;
            w1->str[w1->suns] = '\0';
            if(w1->suns == 49)
            {
                printf("Слишком много связей !");
                exit(1);
            }
        }
        w1 = w1->next;
    }
    clrscr();
    printf("\n\n Матрица инциндентности :\n");
    for(i=1; i<=tops; i++)
    {
        printf("\n %d) ", i);
        for(j=1; j<=tops; j++)
        {
            printf("%d ", Connected(i, j));
        }
    }
    printf("\n\n Нажмите любую клавишу\ldots ");
    getch();
}

Программа 2.Поиск вершин, недостижимых из заданной вершины графа.

//Поиск вершин, недостижимых из заданной вершины графа.
//Программа реализована на языке программирования Turbo-C++

\begin{verbatim}
#include <iostream.h>
#include <fstream.h>
//- - - - - - - - - - - - - - - - - - - - - -
int n,s;
int c[20][20];
int r[20];
//- - - - - - - - - - - - - - - - - - - - - -
int load();
int save();
int solve();
//- - - - - - - - - - - - - - - - - - - - - -
int main(){
  load();
  solve();
  save();
  return 0;
}
//- - - - - - - - - - - - - - - - - - - - - -
int load(){
  int i,j;
  ifstream in("input.txt");
  in"n"s;
  s--;
  for (i=0; i<n; i++)
    for (j=0; j<n; j++)
      in"c[i][j];
  in.close();
  return 0;
}

int save(){
  int i;
  ofstream out("output.txt");
  for (i=0; i<n; i++)
   if (r[i]==0)
    out"i+1"" ";
  out.close();
  return 0;
}
//- - - - - - - - - - - - - - - - - - - - - -
int solve(){
  int i,h,t;
  int q[400];
  for (i=0; i<n+1; i++) q[i]=0;
  r[s]=1;
  h=0;
  t=1;
  q[0]=s;
  while (h<t){
    for (i=0;i<n;i++)
      if ((c[q[h]][i]>0)(r[i]==0)){
    q[t]=i;
    t++;
    r[i]=1;
      }
    h++;
  }
  return 0;
}

Программа 3. Поиск циклов в графе.

{>
Реализация на Turbo-Pascal.
Поиск циклов в графе
<}

{$R-,I-,S-,Q-}

const MAXN       = 40;
      QUERYSIZE  = 600;

type vert = record x: integer; s: array [1..MAXN] of integer; end;

var c   : array [1..MAXN,1..MAXN] of integer;
    n   : integer;

wr  : vert;

res : array [1..MAXN] of string;
    resv: integer;
    ss  : string;

procedure load;
var i,j: integer;
begin
  assign(input,'input.txt');
  reset(input);
   read(n);
   for i:=1 to n do
     for j:=1 to n do
       read(c[i][j]);
  close(input);
end;

function saveway(i:integer):string;
var e:string;
begin
  str(i,e);
  if (wr.s[i]=-1) then
    saveway:=e+' '
  else
    saveway:=saveway(wr.s[i])+e+' ';
end;

p>function findss(s: string): boolean;
var i         : integer;
    l1,l2,rs  : string;
    i1,i2,i22 : integer;

begin
  findss:=false;
  l2:=copy(s,1,pos(' ',s)-1);
  i2:=length(l2);
  i22:=length(s);
  for i:=1 to resv do begin
    l1:=copy(res[i],1,pos(' ',res[i])-1);
    i1:=length(l1);
    rs:=copy(res[i],1,length(res[i])-i1)+res[i];
    if (length(res[i])+i2=i22+i1)and(pos(s,rs)>0)
    then begin
      findss:=true;
      exit;
    end;
  end;
end;

procedure solve;
var h,t,i,j: integer;
    q      : array [1..QUERYSIZE] of vert;
    e      : string;
begin
   resv:=0;
   fillchar(res,sizeof(res),0);

for i:=1 to n do begin
     fillchar(q[i],sizeof(q[i]),0);
     q[i].x:=i;
     q[i].s[i]:=-1;
   end;

t:=n+1;
   h:=1;
   while h<t do begin
     for i:=1 to n do
       if (c[q[h].x,i]>0) then begin
          if (q[h].s[i]=-1) then begin
            wr:=q[h];
            str(i,e);
            ss:=saveway(q[h].x)+e;
            if (not findss(ss)) then begin
               inc(resv);
               res[resv]:=ss;
            end;
          end;
          if (q[h].s[i]=0) then begin
            q[t]:=q[h];
            q[t].x:=i;
            q[t].s[i]:=q[h].x;
            inc(t);
          end;
       end;
     inc(h);
   end;

close(output);
end;

procedure save;
var i: integer;
begin
  assign(output,'output.txt');
  rewrite(output);
  for i:=1 to resv do
    writeln(res[i]);
  close(output);
end;

begin
  load;
  solve;
  save;
end.
Страницы:

Поиск в глубину

При решении многих задач, касающихся ориентированных графов, необходим эффективный метод систематического обхода вершин и дуг орграфов. Таким методом является метод поиск в глубину. Метод поиска в глубину является основой многих эффективных алгоритмов работы с графами. Предположим, что есть ориентированный граф $$G$$, в котором первоначально все вершины помечены меткой " $$unvisited$$ ". Поиск в глубину начинается с выбора начальной вершины $$v$$ орграфа $$G$$, для этой вершины метка " $$unvisited$$ " меняется на метку " $$visited$$ ". Затем для каждой вершины, смежной с вершиной $$v$$ и не посещаемой раньше, рекурсивно применяется поиск в глубину. Когда все вершины, которых можно достичь из вершины $$v$$, будут рассмотрены, поиск заканчивается. Если некоторые вершины остались не посещенными, то выбирается одна из них и алгоритм повторяется. Этот процесс продолжается до тех пор, пока не будут обойдены все вершины орграфа $$G$$.

Метод получил свое название - поиск в глубину, поскольку поиск не посещенных вершин идет в направлении вглубь до тех пор, пока это возможно. Например, пусть $$x$$ является последней посещенной нами вершиной. Выбираем очередную дугу $$(x,y)$$ (ребро), выходящую из вершины $$x$$. Возможна следующая альтернатива: вершина $$y$$ помечена меткой " $$unvisited$$ "; вершина $$y$$ помечена меткой " $$visited$$ ". Если вершина $$y$$ уже посещалась, то отыскивается другая вершина, смежная с вершиной $$x$$ ; иначе вершина $$y$$ метится меткой " $$visited$$ " и поиск начинается заново от вершины $$y$$. Пройдя все пути, которые начинаются в вершине $$y$$, возвращаемся в вершину $$x$$, то есть в ту вершину, из которой впервые была достигнута вершина $$y$$. Затем процесс повторяется, то есть продолжается выбор нерассмотренных дуг, исходящих из вершины $$x$$, и так до тех пор, пока не будут исчерпаны все эти дуги.

Алгоритм Дейкстры нахождения кратчайшего пути

Рассмотрим алгоритм нахождения путей в ориентированном графе. Пусть есть ориентированный граф $$G(V,E)$$, у которого все дуги имеют неотрицательные метки (веса дуг), а одна вершина определена как источник. Задача состоит в нахождении весов кратчайших путей от источника ко всем другим вершинам граф $$G(V,E)$$. Здесь длина пути определяется как сумма весов дуг, составляющих путь. Эта задача часто называется задачей нахождения кратчайшего пути с одним источником. Отметим, что мы будем говорить о длине пути даже тогда, когда она измеряется в других, не линейных, единицах измерения, например, во временных единицах или в денежном эквиваленте.

Можно представить орграф $$G(V,E)$$ в виде карты маршрутов рейсовых полетов из одного города в другой. Каждая вершина соответствует городу, а ребро (дуга) $$(v,w)$$ - рейсовому маршруту из города $$v$$ в город $$w$$. Вес дуги $$(v,w)$$ - это время полета из города $$v$$ в город $$w$$. В этом случае решение задачи нахождения кратчайшего пути с одним источником для ориентированного графа трактуется как минимальное время перелета между различными городами.

Для решения поставленной задачи будем использовать "жадный" алгоритм, который называют алгоритмом Дейкстры (Dijkstra). Алгоритм строит множество $$S$$ вершин, для которых кратчайшие пути от источника уже известны. На каждом шаге к множеству $$S$$ добавляется та из оставшихся вершин, расстояние до которой от источника меньше, чем для других оставшихся вершин. Если веса всех дуг неотрицательны, то можно быть уверенным, что кратчайший путь от источника к конкретной вершине проходит только через вершины множество $$S$$. Назовем такой путь особым. На каждом шаге алгоритма используется также массив $$M$$, в который записываются длины кратчайших особых путей для каждой вершины. Когда множество $$S$$ будет содержать все вершины орграфа, то есть для всех вершин будут найдены особые пути, тогда массив $$M$$ будет содержать длины кратчайших путей от источника к каждой вершине.

Алгоритм Флойда нахождения кратчайших путей между парами вершин

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

Формулировка задачи.Есть ориентированный граф $$G(V,E)$$, каждой дуге (ребру) $$(v,w)$$ этого графа сопоставлен неотрицательный вес $$C_{vw}$$. Общая задача нахождения кратчайших путей заключается в нахождении для каждой упорядоченной пары вершин $$v,w$$ любого пути от вершины $$v$$ в вершину $$w$$, длина которого минимальна среди всех возможных путей от $$v$$ к $$w$$ .

Можно решать эту задачу, последовательно применяя алгоритм Дейкстры для каждой вершины, объявляемой в качестве источника. Но мы для решения поставленной задачи воспользуемся алгоритмом, предложенным Флойдом (R.W. Floyd). Пусть все вершины орграфа последовательно пронумерованы от 1 до $$n$$. Алгоритм Флойда использует матрицу $$A(n \times n)$$, в которой находятся длины кратчайших путей:

$$A_{ij} = C_{ij}$$, если $$i \ne j$$ ;

$$A_{ij} = 0$$, если $$i = j$$ ;

$$A_{ij} = \infty$$ если отсутствует путь из вершины $$i$$ в вершину $$j$$.

Над матрицей $$A$$ выполняется $$n$$ итераций. После $$k$$ -й итерации $$A_{ij}$$ содержит значение наименьшей длины пути из вершины $$i$$ в вершину $$j$$, причем путь не проходит через вершины с номерами большими $$k$$.

Вычисление на $$k$$ -ой итерации выполняется по формуле: $$A_{ij}^k = \min (A_{ij}^{k - 1},A_{ik}^{k - 1},A_{kj}^{k - 1} )$$ Верхний индекс $$k$$ обозначает значение матрицы $$A$$ после $$k$$ -ой итерации.

Для вычисления $$A_{ij}^k$$ проводится сравнение величины $$A_{ij}^{k -1}$$ (то есть стоимость пути от вершины $$i$$ к вершине $$j$$ без участия вершины $$k$$ или другой вершины с более высоким номером) с величиной $$A_{ik}^{k - 1} + A_{kj}^{k - 1}$$ (стоимость пути от вершины $$i$$ к вершине $$k$$ плюс стоимость пути от вершины $$k$$ до вершины $$j$$ ). Если путь через вершину $$k$$ дешевле, чем $$A_{ij}^{k - 1}$$, то величина $$A_{ij}^k$$ изменяется. Рассмотрим орграф:

(рис 16.1) Помеченный орграф

Матрица A(3 * 3) на нулевой итерации (k = 0)

$$\left[ {\begin{array}{*{20}c} 0 8 5 \\ 3 0 \infty \\ \infty 2 0 \\ \end{array} } \right]$$

Матрица A(3 * 3) после первой итерации (k = 1)

$$\left[ {\begin{array}{*{20}c} 0 8 5 \\ 3 0 8 \\ \infty 2 0 \\ \end{array} } \right]$$

Матрица A(3 * 3) после второй итерации (k = 2)

$$\left[ {\begin{array}{*{20}c} 0 8 5 \\ 3 0 8 \\ 5 2 0 \\ \end{array} } \right]$$

Матрица A(3 * 3) после третьей итерации (k = 3)

$$\left[ {\begin{array}{*{20}c} 0 7 5 \\ 3 0 8 \\ 5 2 0 \\ \end{array} } \right]$$

Программы

Программа 1. Построение матрицы инциндентности.

//Построение матрицы инциндентности
//Программа реализована на языке программирования Turbo-C++

\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <iostream.h>

struct elem
{
    int num;  /* Номер вершины */
    int suns; /* Количество сыновей */
    char str[20]; /* Строка с номерами сыновей */
    elem *next; /* Указатель на следующую вершину */
} *head, *w1, *w2;

int Connected(int i, int j)
{
    int k;
    char *str1;
    w2 = head;
    if(i == j) return 0;
    for(k=1; k<i; k++)
        w2 = w2->next;
    if( strchr(w2->str, j) ) return 1;
    return 0;
}

void main()
{

int tops;
    int i,j,k,l;
    char *str1;

clrscr();
    printf("Введите количество вершин  \n");
    scanf("%d", tops);

head = (elem *)malloc(sizeof(elem));
    head->num = 1;
    head->suns = 0;
    head->str[0] = '\0';
    head->next = NULL;

w1 = head;

for(i=2;i<=tops;i++)
    {
        w2 = (elem *)malloc(sizeof(elem));
        w2->num = i;
        w2->suns = 0;
        w2->str[0] = '\0';
        w2->next = NULL;

w1->next = w2;
        w1 = w2;
    }

w1 = head;

for(i=1; i<=tops; i++)
    {
//      clrscr();
        printf("Введите количество путей из вершины  %d\n", i);
        scanf("%d", k);

for(j=1; j<=k; j++)
        {
            printf("Введите связь %d\n", j);
            scanf("%d", l);
            if((l<=0) || (l > tops))
            {
                printf("Такой вершины нет, повторите попытку\n");
                l = 0;
                j--;
                continue;
            }
            w1->str[w1->suns++] = l;
            w1->str[w1->suns] = '\0';
            if(w1->suns == 49)
            {
                printf("Слишком много связей !");
                exit(1);
            }
        }
        w1 = w1->next;
    }
    clrscr();
    printf("\n\n Матрица инциндентности :\n");
    for(i=1; i<=tops; i++)
    {
        printf("\n %d) ", i);
        for(j=1; j<=tops; j++)
        {
            printf("%d ", Connected(i, j));
        }
    }
    printf("\n\n Нажмите любую клавишу\ldots ");
    getch();
}

Программа 2.Поиск вершин, недостижимых из заданной вершины графа.

//Поиск вершин, недостижимых из заданной вершины графа.
//Программа реализована на языке программирования Turbo-C++

\begin{verbatim}
#include <iostream.h>
#include <fstream.h>
//- - - - - - - - - - - - - - - - - - - - - -
int n,s;
int c[20][20];
int r[20];
//- - - - - - - - - - - - - - - - - - - - - -
int load();
int save();
int solve();
//- - - - - - - - - - - - - - - - - - - - - -
int main(){
  load();
  solve();
  save();
  return 0;
}
//- - - - - - - - - - - - - - - - - - - - - -
int load(){
  int i,j;
  ifstream in("input.txt");
  in"n"s;
  s--;
  for (i=0; i<n; i++)
    for (j=0; j<n; j++)
      in"c[i][j];
  in.close();
  return 0;
}

int save(){
  int i;
  ofstream out("output.txt");
  for (i=0; i<n; i++)
   if (r[i]==0)
    out"i+1"" ";
  out.close();
  return 0;
}
//- - - - - - - - - - - - - - - - - - - - - -
int solve(){
  int i,h,t;
  int q[400];
  for (i=0; i<n+1; i++) q[i]=0;
  r[s]=1;
  h=0;
  t=1;
  q[0]=s;
  while (h<t){
    for (i=0;i<n;i++)
      if ((c[q[h]][i]>0)(r[i]==0)){
    q[t]=i;
    t++;
    r[i]=1;
      }
    h++;
  }
  return 0;
}

Программа 3. Поиск циклов в графе.

{>
Реализация на Turbo-Pascal.
Поиск циклов в графе
<}

{$R-,I-,S-,Q-}

const MAXN       = 40;
      QUERYSIZE  = 600;

type vert = record x: integer; s: array [1..MAXN] of integer; end;

var c   : array [1..MAXN,1..MAXN] of integer;
    n   : integer;

wr  : vert;

res : array [1..MAXN] of string;
    resv: integer;
    ss  : string;

procedure load;
var i,j: integer;
begin
  assign(input,'input.txt');
  reset(input);
   read(n);
   for i:=1 to n do
     for j:=1 to n do
       read(c[i][j]);
  close(input);
end;

function saveway(i:integer):string;
var e:string;
begin
  str(i,e);
  if (wr.s[i]=-1) then
    saveway:=e+' '
  else
    saveway:=saveway(wr.s[i])+e+' ';
end;

p>function findss(s: string): boolean;
var i         : integer;
    l1,l2,rs  : string;
    i1,i2,i22 : integer;

begin
  findss:=false;
  l2:=copy(s,1,pos(' ',s)-1);
  i2:=length(l2);
  i22:=length(s);
  for i:=1 to resv do begin
    l1:=copy(res[i],1,pos(' ',res[i])-1);
    i1:=length(l1);
    rs:=copy(res[i],1,length(res[i])-i1)+res[i];
    if (length(res[i])+i2=i22+i1)and(pos(s,rs)>0)
    then begin
      findss:=true;
      exit;
    end;
  end;
end;

procedure solve;
var h,t,i,j: integer;
    q      : array [1..QUERYSIZE] of vert;
    e      : string;
begin
   resv:=0;
   fillchar(res,sizeof(res),0);

for i:=1 to n do begin
     fillchar(q[i],sizeof(q[i]),0);
     q[i].x:=i;
     q[i].s[i]:=-1;
   end;

t:=n+1;
   h:=1;
   while h<t do begin
     for i:=1 to n do
       if (c[q[h].x,i]>0) then begin
          if (q[h].s[i]=-1) then begin
            wr:=q[h];
            str(i,e);
            ss:=saveway(q[h].x)+e;
            if (not findss(ss)) then begin
               inc(resv);
               res[resv]:=ss;
            end;
          end;
          if (q[h].s[i]=0) then begin
            q[t]:=q[h];
            q[t].x:=i;
            q[t].s[i]:=q[h].x;
            inc(t);
          end;
       end;
     inc(h);
   end;

close(output);
end;

procedure save;
var i: integer;
begin
  assign(output,'output.txt');
  rewrite(output);
  for i:=1 to resv do
    writeln(res[i]);
  close(output);
end;

begin
  load;
  solve;
  save;
end.
Вернуться к учебному плану