Способи задання графів
Можливі кілька різних способів задання графа. Ми розглянемо лише один, який використовуватимемо у нашому проекті.
За допомогою матриці суміжності. Матрицею суміжності неорієнтованого розміченого графа з вершинами називається матриця
А = [Xij], i,j = 1, ..., n, рядки якої відповідають вершинам, а стовпці – ребрам, у якій:
Aij = 1, якщо існує ребро (Xi, Xj);
Aij = 0, якщо вершини Xi, Xj не пов'язані ребром.
Приклад 1. Для графа, зображеного на рисунку 1, складемо матрицю суміжності.
Матриця суміжності для графа, зображеного на рис. 1
A | B | C | D | E | |
A | 0 | 1 | 0 | 0 | 1 |
B | 1 | 0 | 1 | 1 | 1 |
C | 0 | 1 | 0 | 1 | 0 |
D | 0 | 1 | 1 | 0 | 1 |
E | 1 | 1 | 0 | 1 | 0 |
Матриця суміжності однозначно визначає структуру графа. Зауважимо, що петля в матриці суміжності може бути представлена відповідним діагональним елементом. Кратні ребра можна представити, дозволивши елементу матриці бути більшим за 1, але це не прийнято.
Матриця суміжності для графа, зображеного на рис. 2
A | B | C | D | E | |
A | 0 | 1 | 1 | 1 | 1 |
B | 1 | 0 | 0 | 0 | 1 |
C | 1 | 0 | 0 | 1 | 0 |
D | 1 | 0 | 1 | 0 | 0 |
E | 1 | 1 | 0 | 0 | 0 |
Проект «Найпростіша візуалізація графа»
Почнемо з найпростішого. На формі позначимо вершини майбутнього графа, задамо матрицю суміжності та побудуємо неорієнтований граф.
Створили проект C# і додали на форму об'єкт PictureBox. Для активації події onPaint() слід використовувати команду Invalidate(). Ця команда також очищає форму від намальованих фігур.
- Створили проект C# і додали на форму компоненти PictureBox, два dataGridView для вершин і для матриці суміжності, меню та кнопки
- Будуємо нуль-граф:
- Заповнюємо матрицю суміжності:
- Будуємо граф:
- Глобальні змінні:
namespace GraphViz
{
public partial class Form1 : Form
{
#region Глобальні змінні
public BackgroundWorker backgroundWorker1; // Фоновий воркер для обчислень
public List points = new List(); // Список вершин графа
Point F = new Point(0, 0); // Тимчасова точка (увага: '@' замінено на 0, оскільки це помилка)
public Graphics G; // Екземпляр класу Graphics для малювання
public Bitmap myBMP; // Бітова карта для малювання
Pen Pen = new Pen(Color.Green, 3); // Зелений пензель товщиною 3 пікселі
public static int X, Y, XX, YY; // Координати для роботи з графом
public int[,] matr; // Матриця суміжності графа
bool flag = false; // Прапорець для роботи з інтерфейсом
#endregion
public Form1()
{
InitializeComponent();
backgroundWorker1 = new BackgroundWorker(); // Ініціалізація фонового потоку
myBMP = new Bitmap(pictureBox1.Width, pictureBox1.Height); // Створення растрового зображення
G = Graphics.FromImage(myBMP); // Графічний контекст для малювання
points.Clear(); // Очищення списку вершин
dataGridView1.Columns.Clear(); // Очищення таблиці
dataGridView1.Columns.Add("Vertices", "Вершини графа"); // Додавання стовпця
dataGridView1.Columns[0].Width = 75; // Ширина стовпця
}
#region Малювання
///
/// Відображає вершини графа у вигляді зелених кіл
///
public void DrawPoints()
{
Brush vertexBrush = new SolidBrush(Color.Green); // Кисть для заливки вершин
foreach (Point vertex in points)
{
// Малюємо коло з центром у точці вершини (з урахуванням перетворення координат)
G.FillEllipse(vertexBrush, vertex.X - 8, -vertex.Y + 400 - 8, 16, 16);
}
pictureBox1.Image = myBMP; // Оновлюємо зображення
}
#endregion
///
/// Обчислює відстань між двома точками
///
/// Перша точка
/// Друга точка
/// Відстань між точками
public double DistanceBetweenPoints(Point A, Point B)
{
return Math.Sqrt(Math.Pow((A.X - B.X), 2) + Math.Pow((A.Y - B.Y), 2));
}
private void pictureBox1_Click(object sender, EventArgs e)
{
// Обчислюємо координати кліку з урахуванням розташування елементів форми
int clickX = MousePosition.X - this.Location.X - pictureBox1.Location.X - 8;
int clickY = -MousePosition.Y + this.Location.Y + 78 + 400;
// Створюємо кисть для малювання вершин
Brush vertexBrush = new SolidBrush(Color.Green);
// Малюємо вершину у вигляді зеленого кола
G.FillEllipse(vertexBrush, clickX - 8, -clickY + 400 - 8, 16, 16);
// Створюємо та додаємо нову вершину до списку
Point newVertex = new Point(clickX, clickY);
points.Add(newVertex);
// Додаємо запис про вершину у таблицю DataGridView
dataGridView1.Rows.Add($"({clickX}, {clickY})");
// Оновлюємо зображення
pictureBox1.Image = myBMP;
}
///
/// Малює ребра графа на основі матриці суміжності
///
public void DrawEdges()
{
// Налаштування пера для малювання ребер
Pen edgePen = new Pen(Color.DarkViolet, 2);
// Ініціалізація матриці суміжності
matr = new int[points.Count, points.Count];
// Заповнення матриці суміжності з DataGridView
for (int i = 0; i < points.Count; i++)
{
for (int j = i; j < points.Count; j++)
{
matr[i, j] = Convert.ToInt32(dgw.Rows[i].Cells[j].Value);
}
}
// Малювання ребер
for (int i = 0; i < points.Count; i++)
{
for (int j = i; j < points.Count; j++)
{
if (i != j && matr[i, j] == 1)
{
// Перетворення координат вершин
int startX = points[i].X - 5;
int startY = -points[i].Y + 400 - 5;
int endX = points[j].X - 5;
int endY = -points[j].Y + 400 - 5;
// Малювання лінії між вершинами
G.DrawLine(edgePen, startX, startY, endX, endY);
}
}
}
// Оновлення зображення
pictureBox1.Image = myBMP;
}
protected override void OnPaint(PaintEventArgs e)
{
// Очищення полотна білим кольором
G.Clear(Color.White);
// Налаштування пера для осей координат
Pen axisPen = new Pen(Color.DarkGreen, 2);
// Визначення точок для осей координат
Point bottomLeft = new Point(1, 400);
Point bottomRight = new Point(400, 400);
Point topLeft = new Point(1, 1);
Point topRight = new Point(400, 1);
// Малювання осей координат
G.DrawLine(axisPen, bottomLeft, bottomRight); // Горизонтальна вісь
G.DrawLine(axisPen, topLeft, topRight); // Друга горизонтальна лінія
G.DrawLine(axisPen, bottomLeft, topLeft); // Вертикальна вісь
G.DrawLine(axisPen, topRight, bottomRight); // Друга вертикальна лінія
// Налаштування пера для сітки
Pen gridPen = new Pen(Color.FromArgb(50, 0, 0, 0), 1);
// Малювання сітки з кроком 10 пікселів
for (int i = 0; i <= 400; i += 10)
{
G.DrawLine(gridPen, i, 0, i, 400); // Вертикальні лінії сітки
G.DrawLine(gridPen, 0, i, 400, i); // Горизонтальні лінії сітки
}
// Оновлення зображення та малювання елементів
pictureBox1.Image = myBMP;
DrawPoints(); // Малювання вершин
// Малювання ребер, якщо прапорець встановлений
if (flag)
{
DrawEdges();
}
base.OnPaint(e);
}
///
/// Обробник кліку кнопки для створення матриці суміжності
///
private void button4_Click(object sender, EventArgs e)
{
// Очищення існуючих стовпців
dgw.Columns.Clear();
// Додавання стовпців за кількістю вершин
for (int i = 0; i < points.Count; i++)
{
var column = new DataGridViewTextBoxColumn
{
DataPropertyName = $"Column{i}",
Name = i.ToString(),
HeaderText = i.ToString(),
Width = 40 // Оптимальна ширина стовпця
};
dgw.Columns.Add(column);
}
// Додавання рядків та ініціалізація значень
dgw.Rows.Add(points.Count);
// Заповнення матриці нулями
for (int i = 0; i < points.Count; i++)
{
dgw.Rows[i].HeaderCell.Value = i.ToString(); // Нумерація рядків
for (int j = 0; j < points.Count; j++)
{
dgw.Rows[i].Cells[j].Value = 0; // Ініціалізація значень
}
}
}
///
/// Обробник кліку кнопки для відображення ребер графа
///
private void button1_Click(object sender, EventArgs e)
{
this.flag = true; // Встановлення прапорця для малювання ребер
Invalidate(); // Оновлення відображення
}




