Files

84 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Лекционные занятия: Основные определения. Понятие изоморфизма. Ориентированные и неориентированные графы. Взвешенный граф.
Добрый день, уважаемые студенты. Сегодня мы начинаем изучение третьего раздела нашей дисциплины – теории графов. Раздел достаточно большой и очень важный для вашей будущей профессиональной деятельности, поскольку графы лежат в основе многих алгоритмов обработки данных, моделей компьютерных сетей, баз данных, систем искусственного интеллекта и других областей информатики. Наша задача на этой лекции – познакомиться с самыми базовыми понятиями: что такое граф, какими они бывают (ориентированные, неориентированные, взвешенные), что означает изоморфизм графов и почему два графа, нарисованных по-разному, могут быть по сути одинаковыми.
Для начала представьте себе карту автомобильных дорог между городами. Города можно изобразить точками, а дороги между ними – линиями, соединяющими эти точки. Или рассмотрите схему метро: станции – это точки, а перегоны между станциями – линии. А теперь представьте себе компьютерную сеть: компьютеры – это устройства, а кабели или беспроводные соединения – это связи, по которым передаются данные. В социальных сетях пользователи – это точки, а отношения «дружбы» или «подписки» – это связи. Все эти примеры объединяет одна и та же математическая структура, которую называют **графом**.
### Основные определения. Неориентированные графы.
Дадим строгое определение. **Графом** называется пара множеств \( G = (V, E) \), где \( V \) – это непустое множество объектов, которые называются **вершинами** (или узлами), а \( E \) – это множество **ребер**, каждое из которых соединяет две вершины (возможно, одну и ту же). Обычно вершины обозначают буквами или числами \( v_1, v_2, \dots \), а ребра как \( \{v_i, v_j\} \) или просто \( v_i v_j \). Важно понимать, что в таком определении ребро не имеет направления: ребро \( \{u, v\} \) и ребро \( \{v, u\} \) – это одно и то же. Такой граф называется **неориентированным**. При этом вершины считаются соединенными, если между ними есть ребро. Сами ребра на рисунках изображаются линиями без стрелок.
Различают несколько видов неориентированных графов. Если между двумя вершинами может быть не более одного ребра и нет ребер, которые начинаются и заканчиваются в одной вершине, такой граф называют **простым**. Однако в некоторых задачах полезны более общие конструкции. Например, если между одной и той же парой вершин допускается несколько различных ребер, то такие ребра называют **кратными**, а граф **мультиграфом**. Кроме того, ребро, которое соединяет вершину саму с собой, называется **петлей**. Граф, в котором есть петли или кратные ребра, иногда называют **псевдографом**. В нашем курсе мы в основном будем работать с простыми графами, но о существовании таких уточнений следует помнить.
Каждая вершина в неориентированном графе обладает важной характеристикой – **степенью**. Степень вершины – это количество ребер, инцидентных этой вершине (то есть тех, у которых она является одним из концов). При подсчете степени петля обычно дает вклад 2, поскольку она соединяет вершину с самой собой, но в простых графах петель нет. Сумма степеней всех вершин в любом графе всегда равна удвоенному числу ребер, так как каждое ребро вносит вклад в степени двух своих концов. Это свойство называется леммой о рукопожатиях.
### Ориентированные графы.
Теперь представим себе другую ситуацию. Например, в социальной сети пользователь A может подписаться на пользователя B, но не обязательно наоборот. Или на карте города дороги могут быть с односторонним движением. В компьютерной сети данные могут передаваться от одного узла к другому только в определенном направлении (например, при запросе клиента к серверу). В таких случаях ребру нужно приписать направление. Так возникает понятие **ориентированного графа** (или **орграфа**).
Формально ориентированный граф задается парой \( G = (V, X) \), где \( V \) – по-прежнему множество вершин, а \( X \) – множество **дуг**. Каждая дуга представляет собой упорядоченную пару вершин \( (u, v) \), где \( u \) **начало** дуги, а \( v \) **конец**. На рисунке дугу изображают стрелкой, идущей от \( u \) к \( v \). Обратите внимание, что дуги \( (u, v) \) и \( (v, u) \) – это разные дуги, если только они обе не присутствуют в графе. В ориентированном графе также могут быть петли – дуги, у которых начало и конец совпадают.
В ориентированном графе для каждой вершины вводятся две характеристики: **полустепень исхода** (количество дуг, выходящих из вершины) и **полустепень захода** (количество дуг, входящих в вершину). Сумма всех полустепеней исхода равна сумме всех полустепеней захода и равна общему числу дуг. Это естественно, потому что каждая дуга имеет одно начало и один конец.
Важно понимать, что любой неориентированный граф можно превратить в ориентированный, заменив каждое ребро \( \{u, v\} \) на две противоположно направленные дуги \( (u, v) \) и \( (v, u) \). Такой процесс называется **ориентацией** графа, хотя иногда под ориентацией понимают произвольное придание направления каждому ребру, в результате чего получается орграф без кратных дуг.
### Взвешенные графы.
В реальных задачах часто недостаточно знать только наличие или отсутствие связи между вершинами. Например, в дорожной сети важно не только то, есть ли дорога между городами, но и ее длина, время в пути или стоимость проезда. В компьютерной сети может быть важна пропускная способность канала связи. Для учета таких количественных характеристик используется понятие **взвешенного графа**.
Взвешенным называется граф (как ориентированный, так и неориентированный), каждому ребру или каждой дуге которого поставлено в соответствие некоторое число – **вес**. Вес может быть любым числом: целым, действительным, положительным или даже отрицательным, в зависимости от прикладной задачи. Обычно вес обозначают функцией \( w(e) \) или \( w(u, v) \). Для неориентированного графа вес не зависит от порядка вершин: \( w(u, v) = w(v, u) \). Для ориентированного графа веса дуг \( (u, v) \) и \( (v, u) \) могут быть разными. На рисунках взвешенные графы часто изображают, подписывая веса рядом с ребрами или дугами.
Зачем нужны взвешенные графы? Они позволяют решать задачи оптимизации, такие как поиск кратчайшего пути (например, в навигаторе), построение минимального остовного дерева (о чем мы будем говорить на следующих занятиях), распределение потоков данных в сети и многие другие. Обратите внимание, что понятие веса не связано напрямую с понятием ориентации – они независимы. Поэтому возможны четыре комбинации: неориентированный граф без весов, ориентированный граф без весов, неориентированный взвешенный граф, ориентированный взвешенный граф.
### Понятие изоморфизма графов.
До сих пор мы говорили о графах как о наборах вершин и ребер, которые можно рисовать на плоскости. Однако один и тот же граф можно изобразить совершенно по-разному: расположить вершины в другом порядке, искривить ребра, переименовать вершины. Возникает естественный вопрос: как определить, что два графа, нарисованные по-разному, представляют одну и ту же структуру? Для этого вводится понятие **изоморфизма графов**.
Представьте, что у вас есть два графа \( G = (V, E) \) и \( H = (W, F) \). Говорят, что эти графы **изоморфны**, если существует взаимно однозначное соответствие (биекция) \( f: V \to W \) между вершинами этих графов, которое сохраняет отношение смежности. Для неориентированных графов это означает, что две вершины \( u \) и \( v \) в графе \( G \) соединены ребром тогда и только тогда, когда их образы \( f(u) \) и \( f(v) \) соединены ребром в графе \( H \). Для ориентированных графов условие формулируется так: существует дуга из \( u \) в \( v \) в графе \( G \) тогда и только тогда, когда существует дуга из \( f(u) \) в \( f(v) \) в графе \( H \). Если графы взвешенные, то дополнительно требуется совпадение весов соответствующих ребер.
По сути, изоморфизм означает, что графы отличаются только названиями вершин и способом изображения, но их внутренняя структура одинакова. Например, треугольник (три вершины, каждая соединена с каждой) изоморфен любому другому треугольнику, даже если вершины переименованы. Однако граф, представляющий собой квадрат (четыре вершины в цикле), не изоморфен графу, состоящему из двух изолированных ребер, потому что у них разное число связей.
Как на практике определить, изоморфны два графа или нет? Иногда это можно сделать, перебирая возможные отображения, но для больших графов такой перебор невозможен из-за комбинаторного взрыва. Поэтому используют **инварианты изоморфизма** – характеристики графа, которые сохраняются при изоморфизме. Если для двух графов эти характеристики различаются, то графы заведомо не изоморфны. К простейшим инвариантам относятся: число вершин, число ребер, степени вершин, последовательность степеней (отсортированный список степеней всех вершин), число компонент связности, наличие циклов определенной длины и так далее. Однако эти инварианты не являются полными: существуют неизоморфные графы с одинаковым числом вершин, ребер и даже одинаковыми последовательностями степеней. Для полного решения задачи изоморфизма в общем случае не известно эффективного (полиномиального) алгоритма, но для многих практических случаев можно справиться с помощью специальных методов. В нашем курсе мы будем использовать изоморфизм в основном для распознавания простых ситуаций, например, на небольших графах.
Почему важно понимать изоморфизм? Потому что при построении моделей реальных систем мы часто отождествляем графы, которые получаются переименованием объектов. Например, топология компьютерной сети не зависит от того, как названы серверы – важна лишь схема соединений. Поэтому два графа, задающих одну и ту же сеть, считаются одинаковыми, то есть изоморфными.
### Способы задания графов.
Прежде чем перейти к практике, кратко охарактеризуем основные способы, с помощью которых граф можно описать, чтобы затем вводить его в компьютерные программы. На следующем практическом занятии вы будете подробно работать с этими способами, но сейчас важно иметь общее представление.
Первый и самый наглядный – **геометрический** (или рисунок). Но он удобен только для небольших графов и не пригоден для алгоритмической обработки.
Второй способ **матрица смежности**. Для графа с \( n \) вершинами строится квадратная таблица (матрица) размера \( n \times n \), в которой элемент на пересечении строки \( i \) и столбца \( j \) равен 1, если существует ребро (или дуга) из вершины \( i \) в вершину \( j \), и 0 в противном случае. Для неориентированного графа матрица смежности симметрична относительно главной диагонали. Для взвешенного графа вместо 1 записывают вес ребра, а отсутствие ребра обозначают либо 0, либо специальным символом (например, бесконечностью), чтобы не путать с нулевым весом.
Третий способ **матрица инцидентности**. Эта матрица имеет размеры \( n \times m \), где \( n \) – число вершин, \( m \) – число ребер. Строки соответствуют вершинам, столбцы – ребрам. Для неориентированного графа в столбце, соответствующем ребру \( \{u, v\} \), ставится 1 в строках \( u \) и \( v \), а в остальных строках 0. Для ориентированного графа обычно ставится 1 в строке начала дуги, -1 в строке конца дуги, а для петель – иногда 0 или другое условное значение. Матрица инцидентности менее удобна для большинства алгоритмов, но полезна в некоторых теоретических задачах.
Четвертый способ **список ребер** (или дуг). Просто перечисляются все пары вершин, соединенных ребрами (для ориентированных – упорядоченные пары) с указанием весов, если они есть. Этот способ очень экономичен для разреженных графов (где ребер мало по сравнению с максимально возможным числом).
Пятый способ **список смежности**. Для каждой вершины составляется список всех соседей (для ориентированных – список вершин, в которые ведут дуги из данной вершины). Это, пожалуй, самый часто используемый способ в алгоритмах на графах, потому что он позволяет быстро перебирать соседей и эффективно по памяти.
Конечно. Вот несколько примеров из сферы информационных технологий, которые можно добавить в соответствующие разделы лекции, чтобы студенты лучше поняли, зачем им нужна теория графов.
### Примеры из ИТ для неориентированных графов
1. **Топология компьютерной сети (физическая)**. Представьте офис, в котором несколько компьютеров соединены между собой с помощью Ethernet-кабелей (топология «общая шина» или «звезда»). Компьютеры – это вершины графа, а кабели между ними – это рёбра. Поскольку данные по кабелю можно передавать в обе стороны (дуплексный режим), рёбра не имеют направления. Такой граф помогает анализировать, какие узлы могут обмениваться пакетами напрямую, и выявлять точки отказа (например, повреждённый кабель разрывает связь).
2. **Схема соединения процессоров в многопроцессорной системе** (например, топология «гиперкуб» или «тор»). Процессоры – вершины, коммуникационные каналы – рёбра. Это неориентированный граф, так как передача данных возможна в обе стороны. Анализ степени вершин позволяет оценить нагрузку на каждый процессор и количество каналов, необходимых для построения отказоустойчивой системы.
### Примеры из ИТ для ориентированных графов
1. **Ссылочная структура веб-сайта**. Страницы сайта – это вершины, а гиперссылки, ведущие с одной страницы на другую, – это дуги. Ссылка действует только в одном направлении: если страница A ссылается на страницу B, это не означает, что B обязательно ссылается на A. Такой орграф используется поисковыми системами (например, в алгоритме PageRank) для ранжирования страниц: чем больше входящих ссылок с авторитетных страниц, тем выше вес (важность) страницы.
2. **Граф вызовов функций в программе**. В прикладном программном обеспечении или операционной системе функция A может вызывать функцию B. Это направленное отношение. Построив ориентированный граф (где вершины – функции, а дуги – вызовы), можно обнаружить циклические зависимости (например, рекурсию или взаимную рекурсию) и выявить потенциально опасные ситуации вроде бесконечного цикла или переполнения стека.
### Примеры из ИТ для взвешенных графов
1. **Маршрутизация пакетов в компьютерной сети**. Каждое ребро (соединение между двумя маршрутизаторами) имеет вес – например, задержку в миллисекундах, пропускную способность (чем больше пропускная способность, тем меньше вес) или стоимость передачи данных. Алгоритмы маршрутизации (OSPF, EIGRP) строят маршруты с минимальной суммой весов, то есть находят кратчайший путь в взвешенном ориентированном или неориентированном графе. Без весов невозможно выбрать оптимальный путь среди нескольких равных по длине каналов.
2. **Сжатие данных с использованием алгоритма Хаффмана**. Хотя это не совсем классический граф, но построение оптимального префиксного кода основано на взвешенном бинарном дереве (дерево – частный случай графа). Частота появления символа во входном потоке служит весом листовой вершины. Дерево строится так, чтобы наиболее частые символы имели более короткие коды, что уменьшает итоговый размер данных.
### Примеры из ИТ для изоморфизма графов
1. **Поиск одинаковых схем в интегральных схемах (EDA-инструменты)**. При проектировании цифровых микросхем логический вентиль (AND, OR, NOT) и его соединения с другими вентилями образуют граф. Инструменты автоматизации проектирования (например, Synopsis, Cadence) сравнивают фрагменты схем на изоморфизм, чтобы обнаружить повторяющиеся блоки и оптимизировать размещение элементов на кристалле. Если два фрагмента изоморфны (с точностью до переименования вершин), они могут быть заменены одним стандартным библиотечным элементом.
2. **Сопоставление структур баз данных или XML-схем**. Представьте две реляционные схемы от разных поставщиков программного обеспечения. Если игнорировать названия таблиц и атрибутов, но сохранить структуру связей (внешние ключи), то изоморфизм графов позволяет определить, совместимы ли эти схемы для миграции данных или для работы интеграционного адаптера. На практике используют более сложные алгоритмы (изоморфизм с учётом типов данных), но базовая идея та же.