
- •Д.Г. Хохлов
- •Оглавление
- •Предисловие
- •1. Основные понятия
- •2. Проектирование программы
- •2.1. Постановка и анализ задачи
- •2.2. Внешнее проектирование
- •2.2.1. Методика внешнего проектирования
- •2.2.2. Внешнее представление данных
- •2.3. Проектирование структуры программы
- •2.4. Проектирование модуля
- •2.4.1. Этапы проектирования модуля
- •2.4.2. Стиль программирования
- •2.4.3. Пример проектирования модуля
- •3. Отладка программы
- •3.1. Планирование отладки
- •3.2. Проектирование тестов
- •3.3. Отладочные средства
- •5.1.2. Файл проекта
- •6.2. Выполнение и оформление работы
- •6.2.1. Задание
- •6.2.2. Описание применения
- •6.2.3. Описание программы
- •6.2.3. Подготовка к отладке программы
- •6.2.4. Отладка программы
- •6.2.5. Заключение
- •6.2.6. Общие правила оформления
- •Список литературы
- •Приложение. Пример выполнения курсовой работы
- •1. Задание
- •2. Описание применения
- •2.1. Постановка задачи
- •2.2. Обращение к программе
- •2.3. Входные данные
- •2.4. Выходные данные
- •2.5. Сообщения
- •2.5.1. Информационные сообщения
- •2.5.2. Сообщения об ошибках
- •3. Описание программы
- •3.1. Метод решения задачи
- •3.2. Структура программы
- •3.3. Описание модулей
- •3.3.1. Main - главный модуль
- •3.3.2. Pminc - поиск минимального цикла
- •3.3.3. Vvodg - ввод графа
- •3.3.4. Vyvodp - вывод пути
- •4. Подготовка к отладке программы
- •4.1. План отладки
- •4.2. Проектирование тестов
- •4.2.1. Тесты черного ящика
- •4.2.2. Тесты белого ящика
- •4.3. Отладочные средства
- •1. Отладка программы
- •3. Заключение
- •Список литературы
- •Приложение 1. Системные файлы проекта
- •Приложение 2. Текст программы модуля main
- •Приложение 3. Текст программы модуля pminc
- •Приложение 4. Текст программы модуля vvodg
- •Приложение 5. Текст программы модуля vyvmsm
- •Приложение 6. Текст программы модуля vyvodp
- •Приложение 7. Текст программы модуля vyvsoob
- •Приложение 8. Текст отладочной программы драйвера dvvodg
- •Приложение 9. Результаты тестирования программы
- •Приложение 10. Трудоемкость курсовой работы
- •Приложение 11. Дневник выполнения курсовой работы
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]).