Введение

Что такое граф? Граф - фундаментальное понятие дискретной математики, комбинация набора вершин и набора ребер. Чтобы лучше понять, что такое граф - представьте дорожную систему некоторой страны N.

Пусть в нашем государстве N 6 городов. Эти города связаны дорогами таким образом, как показано на схеме. Создание программ На этой схеме изображен граф. Этот граф имеет 6 вершин и 6 ребер.

Также, дороги в нашей стране могут быть как односторонними, так и двухсторонними. В теории графов приняты следующие термины - графы с односторонними ребрами называют ориентированными, иначе - неориентированными. До этого наш граф был неориентированным, теперь - ориентированным. Создание программ Также мы можем присвоить ребрам графа какой-либо параметр, например, стоимость проезда по дороге. Теперь наш граф стал взвешенным. Создание программ Путём в графе называется последовательность вершин, каждая из которых соединена со следующей вершиной ребром. Граф называют связным, если между любой парой вершин существует хотя бы один путь.

Циклы в графе

Иногда бывает так, что первая вершина, с которой мы начинаем наш путь, совпадает с последней. В этом случае мы можем сказать, что граф имеет цикл. Создание программ

Так, вершины 3,5,6 связаны циклом.

Особые графы

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

Дерево

Дерево - структура данных, связный граф, не имеющий циклов. Ребра дерева неориентированы и невзвешены. Создание программ Дерево - это связный граф без циклов, петель и кратных рёбер.

Создание графа и методы представления

Существует два способа представления графа. Первый из них - матрица смежности. Этот способ достаточно просто реализуется. Пусть у нас есть граф из N вершин, мы создаем матрицу (двумерный массив) \(N * N\), где будем хранить логические значения. Если путь из вершины i в вершину j существует, то \(graph[i][j] = true\), в противном случае - \(false\).

Реализуем следующую программу с использованием матрицы смежности: введем вершины графа и выведем матрицу смежности, где “\(+\)” - означает, что путь существует.

bool graph[100][100] = { false };
int n;// количество ребер
int m;// количество вершин
cout << "enter a number of edges: ";
cin >> n;
cout << "enter a number of vertexes: ";
cin >> m;
for (int i = 1; i <= n; i++)
{
	int u, v;
	сin >> u >> v;
	graph[u][v] = graph[v][u] = true;// граф неориентированный - можем двигаться в обе стороны
  }
cout << "Matrix: " << endl;
for (int i = 0; i < m; i++)
{
	for (int j = 0; j < m; j++)
	{
		if (graph[i][j])
			cout << "+" << " ";
		else
			cout << "." << " ";
	}
	cout << endl;
}
return 0;

У матрицы смежности есть свои преимущества и недостатки. Мы можем проверить, существует ли ребро между двумя вершинами за \(0(1)\). Очевидно, что матрица занимает \(N^2\) памяти, что является неприемлемым для больших графов. В такой ситуации мы вынуждены искать оптимальное решение.

Второй способ представления графа - список смежности. Его идея заключается в хранении для каждой вершины расширяемого массива (вектора), содержащего всех её соседей.

Теперь для каждой вершины будем выводить количество вершин, смежных с ней.

vector <int> graph[100];
int n, m;
cout << "enter a number of edges: ";
cin >> n;
cout << "enter a number of vertexes: ";
cin >> m;
int c = 0;

for (int i = 0; i < n; i++) {
	int u, v; 
	cin >> u >> v;
	u--, v--;// так как нумерация с нуля

	graph[u].push_back(v);
	graph[v].push_back(u);
}

for (int i = 0; i < m; i++) {
	int c = 0;
	for (int v : graph[i]) {    
		c++;                    
	}                           

	cout << c << " edges adjacent to vertex " << i + 1 << endl;
}

Cписок смежности более оптимален по памяти и по времени, чем матрица смежности. Однако, следует учитывать особенности поставленной задачи и выбирать наиболее оптимальный вариант из предложенных.