Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2011 / 2011 / UP_MODPR_.RTF
Скачиваний:
48
Добавлен:
12.03.2015
Размер:
541.34 Кб
Скачать

2.4. Выходные данные

Результатом работы программы являeтся текст, содержащий матрицу смежности входного графа и последовательность сообщений, выводимые в выходной файл, указанный при вызове программы (см. раздел 2.2). Если выходной файл не указан, то результаты выводятся на экран дисплея. Если исходные данные вводятся с клавиатуры, то они появятся на экране. Возможные сообщения приведены в разделе 2.5.

Введите граф (количество вершин от 1 до 20 и ребра, конец Ctrl-Z).

5

0 2

4 2

2 3

4 3

2 0

1 3

1 0 ^Z

Предупреждение: было дублирование ребер (игнорировалось)

Матрица смежности графа

0 1 1 0 0

1 0 0 1 0

1 0 0 1 1

0 1 1 0 1

0 0 1 1 0

Кратчайший цикл длиной 3:

2 3 4 2

Рис. 2.3. Пример результата работы программы

Результаты обработки графа, показанного на рис. 2.1, приведены на рис. 2.3. Предполагается, что входной и выходной файлы не заданы, т. е. использованы клавиатура и экран. Сделано предупреждение, т. к. ребро 0 - 2 введено дважды.

2.5. Сообщения

Выходные данные программы могут содержать сообщения, перечисленные в разделах 2.5.1 и 2.5.2. В угловых скобках указаны названия вставляемых в сообщения величин.

2.5.1. Информационные сообщения

1. Кратчайший цикл длиной <длина>:

<перечень вершин>

2. В графе нет циклов.

3. Введите граф (колич.вершин от 1 до 20 и ребра, конец Ctrl-Z).

При вводе с клавиатуры необходимо ввести целое число, затем вводить пары целых чисел - номера вершин графа, по правилам, описанным в 2.3.

2.5.2. Сообщения об ошибках

4. Ошибка: нет исходных данных.

5. Ошибка: количество вершин должно быть от 1 до 20.

6. Ошибка: номер вершины должен быть от 0 до <число>.

7. Ошибка: ребро должно содержать две вершины.

8. Решение прекращено.

Выдается после сообщений 4 - 7.

9. Предупреждение: было дублирование ребер (игнорировалось).

Необходимо проверить, нет ли ошибки при вводе ребра.

10. Предупреждение: граф содержит петли (игнорируются).

3. Описание программы

3.1. Метод решения задачи

В литературе [1, 2] отсутствуют методы поиска кратчайшего цикла. Поэтому в программе использован полный перебор всех путей графа методом поиска с возвратом [2]. Выбран вариант этого метода - обход графа в глубину, т. к. при обходе в ширину трудно запоминать пройденный путь. Метод вычисления степеней матрицы смежности в данном случае неудобен, поскольку трудно следить, чтобы искомый цикл не содержал повторяющихся ребер.

Поиск с возвратом - это универсальный метод полного перебора вариантов для решения задач вида "найти все возможные способы (хотя бы один способ) ... " [2, 1]. Решение задачи ищется как последовательность элементов

е[1], е[2], ... , е[k]

(k <= R, R может быть неизвестно). Каждый элемент решения e[k] выбирается путем перебора из множества альтернатив (вариантов) A[k], в общем случае зависящего от предыдущих элементов e[1], ... , e[k-1].

В случае тупика, когда для элемента e[k] все альтернативы из множества A[k] уже рассмотрены, происходит возврат на один элемент назад, аналогично рассматривается следующая альтернатива для элемента a[k-1] и т.д.

Рекурсивный алгоритм поиска с возвратом проще итеративного [2 с. 110 - 112], но тратит больше времени и памяти за счет рекурсивных вызовов. Поэтому использован итеративный алгоритм, т. к. он не слишком сложен.

Выбранный метод конкретизирован в алгоритме 3.1 для задачи поиска кратчайшего цикла как перебор всех возможных путей обходом графа в глубину [1 с. 125].

Алгоритм 3.1. Поиск с возвратом кратчайшего цикла графа

/* Поиск кратчайшего цикла обходом графа в глубину */

dcmin = n + 1; /* длина минимального цикла (3..n) */

for (v[0]=0; v[0]<n; v[0]++) /* начальная вершина: 0..n-1 */

{ /* Обход в глубину дерева путей, начинающихся с v[0] */

k = 1; v[1] = 0; /* начальный номер преемников v[0] */

do

{ Найти номер вершины vn очередного преемника v[k-1];

if (есть vn) /* есть путь вперед */

{ v[k] = vn; /* вперед: vn - в стек */

v[k+1] = 0; /* начальный номер преемников v[k] */

If (v[0]...v[k] - цикл)

if (k < dcmin)

{ dcmin = k;

c[0]...c[k] = v[0]...v[k]; /* запомнить цикл */

}

k++;

}

else /* назад */

{ v[k]++; /* следующий преемник v[k-1] */

k--; /* удалить v[k] из стека */

}

}

while (k > 0); /* стек не пуст */

}

Перебор путей по алгоритму 3.1 сокращен, как показано в алгоритме 3.3, за счет использования следующих правил - эвристик (в скобках приведена соответствующая формальная запись).

1. Прекратить поиск, обнаружив цикл длиной 3 (dcmin == 3).

2. Отвергать пути длиннее минимального из найденных циклов или равные ему (k >= dcmin). Поэтому, найдя цикл, можно удалить из стека две вершины.

3. Отвергать пути, ведущие в вершину, ранее использованную в качестве начальной (vn < v[0]), т.к. все проходящие через нее циклы уже просмотрены. По этой причине перебор по возрастанию возможных номеров очередной вершины пути начинать не с 0, а с начальной вершины текущего пути (v[к+1] = v[0]).