Алгоритм краскала
Введение
Задача о нахождении
Эта задача может быть сформулирована в терминах теории графов как задача о нахождении минимального остовного дерева в графе, вершины которого представляют города, рёбра — это пары городов, между которыми есть маршрут, а вес ребра равен стоимости проезда по соответствующему маршруту.
Существует несколько алгоритмов для нахождения минимального остовного дерева. Некоторые наиболее известные из них перечислены ниже:
- Алгоритм Прима;
- Алгоритм Краскала;
- Алгоритм Борувки.
В данной курсовой работе подробно будет рассмотрен алгоритм Краскала.
1 Анализ и теоретическое
1.1 Постановка задачи.
В ходе выполнения
данного курсового проекта
1.2 Основные понятия теории графов.
Граф – система, которая интуитивно может быть рассмотрена как множество кружков и множество соединяющих их линий(геометрический способ задания графа – см. рисунок 1). Кружки называются вершинами графа, линии со стрелками – дугами, безстрелок – ребрами. Граф, в котором направление линий не выделяется (все линии являются ребрами), называется неориентированным; граф, в котором направление линий принципиально (линииявляются дугами) называется ориентированным.
Рис. 1. Пример графа
Теория графов
может рассматриваться как
Подграфом называется часть графа, образованная подмножеством вершин вместе со всеми ребрами (дугами), соединяющимивершины из этого множества. Если из графа удалить часть ребер(дуг), то получим частичный граф.
Две вершины называются смежными, если они соединены ребром (дугой). Смежные вершины называются граничными вершинами соответствующего ребра (дуги), а это ребро (дуга) – инцидентным соответствующим вершинам. Путем называется последовательность дуг (в ориентированном графе), такая, что конец одной дуги является началом другой дуги. Простой путь – путь, в котором ни одна дуга не встречается дважды. Элементарный путь – путь, в котором ни одна вершина не встречается дважды. Контур – путь, у которого конечная вершина совпадает с начальной вершиной. Длиной пути (контура) называется число дуг пути (или сумма длин его дуг, если последние заданы). Граф, для которого из (i, j) V следует (j, i) V называетсясимметрическим. Если из (i, j) V следует, что (j, i) V, то соответствующий граф называется антисимметрическим.Цепью называется множество ребер (в неориентированномграфе), которые можно расположить так, что конец (в этом расположении) одного ребра является началом другого.Замкнутаяцепь называется циклом.Если любые две вершины графа можно соединить цепью, тограф называется связным. Если граф не является связным, то егоможно разбить на связные подграфы, называемые компонентами. Связностью графа называется минимальное число ребер, после удаления которых граф становится несвязным. Для ориентированных графов, если любые две вершины графа можно соединитьпутем, то граф называется сильно связным. Деревом называется связный граф без простых циклов, имеющий не менее двух вершин. Для дерева m = n – 1, а число висячих вершин равно .
1.3 Минимальные остовные деревья.
Минимальным остовным деревом (МОД) связного взвешенного графа называется его связный подграф, состоящий из всех вершин исходного дерева и некоторых его ребер, причем сумма весов ребер максимально возможная. Если исходный граф несвязен, то описываемую ниже процедуру можно применять поочередно к каждой его компоненте связности, получая тем самым минимальные остовные деревья для этих компонент.
При разработке ,например, электронных схем зачастую необходимо электрически соединить контакты нескольких компонентов. Для соединения множества из n контактов можем использовать некоторую компоновку из n-1 проводов, каждый из которых соединяет два контакта. Обычно желательно получить компоновку, которая использует минимальное количество провода.
Мы можем смоделировать эту задачу при помощи связного неориентированного графа G = (V, E), где V-множество контактов, E-множество возможных соединения между парами контактов, и для каждого ребра
(u,v) ∈E задан вес w (u,v), определяющий стоимость (количество необходимого провода) соединения u и v. Нам нужно найти ациклическое подмножество TE, которое соединяет все вершины и чей общий вес минимален. Поскольку множество Т ациклическое и связывает ве вершины, оно должно образовать дерево, которое мы назовем остовным деревом графа G. Задачу поиска дерева Т мы назовем задачей поиска минимального остовного дерева. На рис.2 Показан пример связного графа и его минимального остовного дерева. На ребрах указан их вес , а ребра минимального остовного дерева отдельно выделены цветом. Общий вес показанного дерева равен 37.
Рис. 2 Минимальное оставное дерево связанного графа.
Приведенное дерево не единственное: удалин ребро (b, c) и заменив его ребром (a, h), мы получин другое остовное дерево с тем же весом 37.
1.4 Построение минимального остовного дерева.
Рассмотрим
общую схему работы алгоритмов построения
минимального остовного дерева с
использованием жадной стратегии. Итак,
пусть дан связный
Искомый остов строится постепенно. Алгоритм использует некоторый ациклический подграфА исходного графа G, который называется промежуточным остовным лесом. Изначально G состоит из n вершин-компонент, не соединенных друг с другом (n деревьев из одной вершины). На каждом шаге в A добавляется одно новое ребро. Граф A всегда является подграфом некоторого минимального остова. Очередное добавляемое ребро e=(u,v) выбирается так, чтобы не нарушить этого свойства: A∪ {e} тоже должно быть подграфом минимального. Такое ребро называется безопасным.
Вот как выглядит общий алгоритм построения минимального остовного дерева:
MST-GENERIC(G,w)
1: A ← 0
2: while (пока) A не является остовом
3: do найти безопасное ребро (u,v) ∈E для A
4: A ← A∪ {(u,v)}
5: returnA
По определению A, он должен оставаться подграфом некоторого минимального остова после любого числа итераций. Конечно, главный вопрос состоит в том, как искать безопасное ребро на шаге 3. Понятно, что такое ребро всегда существует, если A еще не является минимальным остовом (любое ребро остова, не входящее в A). Заметим, что так как A не может содержать циклов, то на каждом шаге ребром соединяются различные компоненты связности (изначально все вершины в отдельных компонентах, в конце A – одна компонента). Таким образом цикл выполняется (n-1) раз.
Далее приводится общее правило отыскания безопасных ребер. Для этого доказана теорема, которая поможет находить безопасные ребра. Предварительно докажем маленькую лемму:
Лемма: пусть Т – минимальное остовное дерево.
Тогда любое ребро е из T – безопасное.
Док-во: в Т – (n-1) ребро. На каждом
шаге Generic-MST мы добавляли одно безопасное
ребро. Всего выполнено (n-1) шагов, следовательно,
все ребра в T – безопасные по определению.
Теорема: Пусть G(V;E) – связный неориентированный
граф и на множестве Е определена весовая
функция w. Пусть А – некоторый подграф
G, являющийся в то же время подграфом некоторого
минимального остовного дерева T. Рассмотрим
компоненту связности К из А. Рассмотрим
множество E(K) ребер графа G, только один
конец которых лежит в К. Тогда ребро минимального
веса из E(K) будет безопасным.
Док-во: Пусть e=(u,v) – минимальное по весу
ребро из E(K). Пусть минимальный остов T не содержит e (в противном случае доказываемое
утверждение очевидно по приведенной
выше лемме). Т.к. T связен, в нем существует
некоторый (единственный) ациклический
путь p из u в v, и e замыкает его в цикл. Поскольку один
из концов e лежит в K, а другой в V \ K, в пути p существует хотя бы одно
ребро e'=(x,y), которое обладает тем же свойством.
Это ребро не лежит в A, т.к. в A пока что нет ребер между K
и V \ K. Удалим из T ребро e' и добавим e. Так как w(e') <w(e), мы получим остовное
дерево T', суммарный вес которого меньше
суммарного веса T. Таким образом, T не является минимальным
остовом. Противоречие. Следовательно, T
содержит e.
В связи с приведенной теоремой введем следующее
Определение.Безопасным ребром e относительно некоторой компоненты связности К из А назовем ребро с минимальным весом, ровно один конец которого лежит в К.
1.5 Теоретическое исследование Алгоритм Краскала.
Алгоритм Краскала объединяет вершины графа в несколько связных компонент, каждая из которых является деревом. На каждом шаге из всех ребер, соединяющих вершины из различных компонент связности, выбирается ребро с наименьшим весом. Необходимо проверить, что оно является безопасным. Безопасность ребра гарантируется ранее доказанной теоремой о безопасных ребрах. Так как ребро является самым легким из всех ребер, выходящих из данной компоненты, оно будет безопасным.
Остается понять, как реализовать выбор безопасного ребра на каждом шаге. Для этого в алгоритме Краскала все ребра графа G перебираются по возрастанию веса. Для очередного ребра проверяется, не лежат ли концы ребра в разных компонентах связности, и если это так, ребро добавляется, и компоненты объединяются.
Удобно использовать для хранения компонент структуры данных для непересекающихся множеств, как, например, списки или, что лучше, лес непересекающихся множеств со сжатием путей и объединением по рангу (один из самых быстрых известных методов). Элементами множеств являются вершины графа, каждое множество содержит вершины одной связной компоненты. Для работы с множествами используются следующие процедуры:
Make-Set(v) |
Создание множества из набора вершин |
Find-Set(v) |
Возвращает множество, содержащее данную вершину |
Union(u,v) |
Объединяет множества, содержащие данные вершины |
Общая схема алгоритма выглядит так:
MST-KRUSKAL(G,w)
1: A ← 0
2: for each (для каждой) вершины v∈V[G]
3: do Make-Set(v)
4: упорядочить ребра по весам
5: for (u,v) ∈E (в порядке возрастания
веса)
6: do if Find-Set(u) ≠ Find-Set(v) then
7: A ← A∪ {(u,v)}
8: Union(u,v)
9: returnA
Пример:
На рисунках К1-К8 представлена работа алгоритма.
|
|
|
|
|
|
|
|
Подсчитаем время работы алгоритма. Будем считать, что для хранения непересекающихся множеств используется метод с объединением по рангу и сжатием путей, т.к. это самый быстрый способ из известных на сегодняшний день. Инициализация занимает время O(V), упорядочение ребер в строке 4 – O(ElogE). Далее производится O(E) операций, в совокупности занимающих время O(Eα’(E,V)), где α’ - функция, обратная к функции Аккермана .Поскольку α’(E,V) = o(logE), общее время работы алгоритма Крускала составляет O(ElogE) (основное время уходит на сортировку).
1.6 Теоретическая оценка
Для теоретической оценки трудоемкости алгоритма необходимо определить количество элементарных операций, которые должны выполнится при запуске программы.
Под элементарными операциями языка высокого уровня, будем понимать операции которые могут быть представлены в виде элементарных конструкций данного языка (но не обязательно в виде одной машинной команды), а именно за одну элементарную операцию будем считать следующие:
1) операцию присваивания a¬b;
2) операцию индексации массива a[
3) арифметические операции *,/,
4) операции сравнения a<b;
5) логические операции or,and,
Отметим, что неявно в операцию сравнения входит машинная команда перехода в конструкции ifthenelse:
F «ветвление» = fthen * p +felse * (1-p).
Цикл не является элементарной операцией, т.к. может быть представлен в виде;
fori¬1 to N
тело Û
end;
Таким образом конструкция цикла требует 1+3*N элементарных операций:
F«цикл» = 1+3*N+N*f«тела цикла».
2 Разработка технологии
2.1 Блок схема программы и ее описание.
Рис.3.Блок-схема алгоритма задачи моделирования
Описание блок-схемы алгоритма задачи моделирования
Блок 1. Ввод матрицы весов ребер графа. Запись графа в память компьютера осуществляется при помощи двумерного массива, который служит матрицей весов ребер графа.
Блок 2. Ввод вершины поиска. После заполнения матрицы весов пользователем программа автоматически определяет вершину начала построения остова.
Блок 3. Поиск ребра минимального веса среди инцидентных n ребер. Программа анализирует матрицу весов и находит ребро с минимальным весом. Найденное ребро сохраняется в переменнуюmin.
Блок 4. Формирование остова. Формируется остов.
Блок
5.Выбор новой инцидентной
Блок 6. Все вершины графа помечены. Если все вершины графа помечены, то поиск остова заканчивается. Если нет, то среди инцидентных помеченным вершинам ребер, за исключением ребер остова и ребер, образующих в остов цикл, происходит поиск ребра минимального веса min и построение остова.
Блок 7. Вывод остова. После того как все вершины графа помечены, на монитор пользователя выводится остов минимального веса.
Блок 8. Инцидентные помеченным вершинам ребра. Если есть такие ребра, то программа анализирует найденные ребра, если нет инцидентных ребер, то программа переходит к Блоку 6.
Блок 9. Ребра остова. Найденное ребро не используется в остове, то программа переходит к Блоку 10, а если используется, то переходит к Блоку 6.
Блок 10. Образует ребро в остове цикл, если да то программа переходит к Блоку 6. Если ребро не образует в остове цикл, то программа переходит к Блоку11.
Блок
11. Нахождение ребра минимального веса.
Программа анализирует
Блок 12. Формирование остова. Программа формирует полученный остов, проверяется связанность ребер с вершинами графа, за это отвечает массивсвязанности ar[jmin, imin], если он равен единицам, то все ребра связаны с вершинами, если он не равен единице, то продолжается формирование остова.
Блок
13. Выбор новой инцидентной
2.2 Код программы.
using System;
usingSystem.Collections.
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Xml;
usingSystem.Collections;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
int n = 1;
float[,] a, a1;
ArrayListkoord = new ArrayList();
public Form1()
{
InitializeComponent();
}
private void control()
{
a = new float[n, n];
a1 = new float[n, n];
bool flag = true;
for (short i = 0; i< n; i++)
for (short j = 0; j < n; j++)
try
{
a[i, j] = Convert.ToSingle(
}
catch
{
a[i, j] = 0;
flag = false;
}
if (flag == false)
{
MessageBox.Show("Введенное
вами значение имеет
return;
}
for (short i = 0; i< n; i++)
for (short j = 0; j < n; j++)
a1[i, j] = Convert.ToSingle(
}
private void numericUpDown1_ValueChanged(
{
n = (byte)numericUpDown1.Value;
dataGridView1.ColumnCount = n;
dataGridView1.RowCount = n;
dataGridView2.ColumnCount = n;
dataGridView2.RowCount = n;
for (short i = 0; i< n; i++)
{
dataGridView1[i, i].Style.BackColor = Color.Gray;
dataGridView1[i, i].Value = 0;
dataGridView1[i, i].ReadOnly = true;
dataGridView2[i, i].Style.BackColor = Color.Gray;
dataGridView2[i, i].Value = 0;
dataGridView2[i, i].ReadOnly = true;
}
}
private void Form1_Load(object sender, EventArgs e)
{
numericUpDown1_ValueChanged(
button1.Enabled = false;
построитьToolStripMenuItem.
button2.Enabled = false;
progressBar1.Hide();
}
private void button2_Click(object sender, EventArgs e)
{
progressBar1.Show();
progressBar1.Maximum = n * n;
progressBar1.Value = 0;
Random x = new Random();
for (short i = 0; i< n; i++)
for (short j = 0; j < n; j++)
{
progressBar1.Value++;
if (i != j)
{
dataGridView1[i, j].Value = x.Next(0, 20);
}
}
progressBar1.Value = progressBar1.Maximum;
progressBar1.Value = progressBar1.Minimum;
progressBar1.Hide();
}
private void button3_Click(object sender, EventArgs e)
{
if (MessageBox.Show("
{
progressBar1.Show();
progressBar1.Value = 0;
progressBar1.Maximum = 2 * n * n;
for (short i = 0; i< n; i++)
{
for (short j = 0; j < n; j++)
{
progressBar1.Value++;
if (i != j)
{
dataGridView1[i, j].Value = null;
dataGridView2[i, j].Value = null;
a[i, j] = 0;
a1[i, j] = 0;
}
}
}
koord.Clear();
n = 1;
numericUpDown1.Value = n;
pictureBox1.Invalidate();
pictureBox2.Invalidate();
progressBar1.Value = 0;
button1.Enabled = false;
progressBar1.Value = progressBar1.Maximum;
progressBar1.Hide();
}
}
private void dataGridView1_CellBeginEdit(
{
if (e.ColumnIndex == e.RowIndex)
e.Cancel = true;
}
private void dataGridView1_
{
bool flag1 = true;
button1.Enabled = true;
try
{
Convert.ToDouble(
dataGridView1[e.ColumnIndex, e.RowIndex].Style.ForeColor = Color.Black;
}
catch
{
dataGridView1[e.ColumnIndex, e.RowIndex].Style.ForeColor = Color.Red;
toolStripStatusLabel1.Text = "Ошибкавкраснойячейке (" + (e.RowIndex + 1) + "," + (e.ColumnIndex + 1) + ")";
flag1 = false;
}
if (flag1)
dataGridView1[e.RowIndex, e.ColumnIndex].Value = dataGridView1[e.ColumnIndex, e.RowIndex].Value;
построитьToolStripMenuItem.
pictureBox1.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Show();
progressBar1.Value = 0;
if (n <= 2)
progressBar1.Maximum = 16;
else
progressBar1.Maximum = n*n*n*n/2;
control();
a1 = newfloat[n, n]; //Матрица весов окончательной матрицы
short[,] b = newshort[n, n]; //Массив компонент (двумерный)
float[] c; //Массив ребер (вещественный)
progressBar1.Value++;
for (short i = 0; i< n; i++)
for (short j = 0; j < n; j++)
b[i, j] = -1;
progressBar1.Value++;
//Заполнение
массива компонент (первая
for(short i = 0; i< n; i++)
b[0, i] = i;
progressBar1.Value++;
short re = 0;
//Проверкачисларебер
for(short i = 0; i< n; i++)
for(short j = 0; j <i; j++)
if(a[i, j] != 0)
re++;
c = new float[re];
re = 0;
progressBar1.Value++;
//Добавление ребер в массив ребер
for(short i = 0; i< n; i++)
for(short j = 0; j <i; j++)
if(a[i, j] != 0)
{
c[re] = a[i, j];
re++;
}
progressBar1.Value++;
//Упорядочение массива ребер по возрастанию
float g; //Обменник (вещественная переменная)
short l;
while(true)
{
l = 0;
for(short i = 1; i< re; i++)
{
if(c[i] < c[i - 1])
{
g = c[i - 1];
c[i - 1] = c[i];
c[i] = g;
l++;
}
}
if(l == 0)
break;
}
progressBar1.Value++;
//Выполнениеалгоритма
short com1 = 0, com2 = 0, n3;
bool flag = false;
for(short k = 0; k < re; k++)
{ //Поискребравматрицевесов
for (short i = 0; i< n; i++)
for (short j = 0; j <i; j++)
{
progressBar1.Value++;
if (c[k] == a[i, j] && c[k] != a1[i, j])
{
//Проверка вершин на
flag = false;
for (short n1 = 0; n1 < n; n1++)
{
for (short n2 = 0; n2 < n; n2++)
if (i == b[n1, n2])
flag = true;
if (flag)
break;
}
flag = false;
for (short n1 = 0; n1 < n; n1++)
{
for (short n2 = 0; n2 < n; n2++)
if (j == b[n1, n2])
flag = true;
if (flag)
break;
}
if (com1 != com2)
{ //Добавление ребра в остовый лес
a1[i, j] = c[k];
a1[j, i] = c[k];
//Обьединение двух соединенных компонент в одну
n3 = 0;
for (short t = 0; t < n; t++)
if (b[t, com1] == -1)
while (b[n3, com2] != -1)
b[n3 + t, com1] = b[n3, com2];
b[n3, com2] = -1;
n3++;
break;
}
}
}
}
//Изъятие использованного ребра из массива ребер
c[k] = 0;
}
progressBar1.Value++;
//На выходе получаем матрицу остовного леса
for (short i = 0; i< n; i++)
for (short j = 0; j < n; j++)
{
dataGridView2[i, j].Value = a1[i, j];
dataGridView2[j, i].Value = a1[i, j];
}
progressBar1.Value++;
progressBar1.Value++;
progressBar1.Value = progressBar1.Maximum;
progressBar1.Value = progressBar1.Minimum;
progressBar1.Hide();
pictureBox2.Invalidate();
}
private void выходToolStripMenuItem_Click(
{
Application.Exit();
}
private void построитьToolStripMenuItem_
{
button1_Click(sender, e);
}
private void слЧислаToolStripMenuItem_
{
button2_Click(sender, e);
}
private void сбросToolStripMenuItem_Click(
{
button3_Click(sender, e);
}
private void сохранитьГрафToolStripMenuItem
{
Point[] pnt = (Point[])koord.ToArray(typeof(
int[] x = new int[pnt.Length];
int[] y = new int[pnt.Length];
for (inti = 0; i<pnt.Length; i++)
{
x[i] = pnt[i].X;
y[i] = pnt[i].Y;
}
progressBar1.Maximum = 2 * n * n;
progressBar1.Value = 0;
control();
SaveFileDialog s = new SaveFileDialog();
s.DefaultExt = ".xml";
s.Filter = "Графвформате *.xml|*.xml";
if (s.ShowDialog() != DialogResult.OK) return;
XmlTextWriter w = new XmlTextWriter(s.FileName, null);
w.Formatting = Formatting.Indented;
w.WriteStartDocument();
w.WriteStartElement ("Структура");
w.WriteStartElement ("Неориентированный_граф");
w.WriteAttributeString( "Вершин", XmlConvert.ToString(n));
for (short i = 0; i< n; i++)
{
w.WriteStartElement("Строка_" + (i + 1));
for (short j = 0; j < n; j++)
{
progressBar1.Value++;
w.WriteAttributeString("Яч_" + (j + 1), XmlConvert.ToString(a[i, j]));
}
w.WriteEndElement();
}
w.WriteEndElement();
w.WriteStartElement ("Остовый_лес");
w.WriteAttributeString ("Вершин", XmlConvert.ToString(n));
for (short i = 0; i< n; i++)
{
w.WriteStartElement ("Строка_" + (i + 1));
for (short j = 0; j < n; j++)
{
progressBar1.Value++;
w.WriteAttributeString("Яч_" + (j + 1), XmlConvert.ToString(a1[i, j]));
}
w.WriteEndElement();
}
w.WriteEndElement();
w.WriteStartElement ("Массив_координат");
w.WriteAttributeString ("Вершин", XmlConvert.ToString(n));
w.WriteStartElement ("Координаты_x");
for (short i = 0; i< n; i++)
w.WriteAttributeString ("В_" + (i + 1), x[i].ToString());
w.WriteEndElement();
w.WriteStartElement("
for (short i = 0; i< n; i++)
w.WriteAttributeString("В_" + (i + 1), y[i].ToString());
w.WriteEndElement();
w.WriteEndElement();
w.WriteEndElement();
w.WriteEndDocument();
w.Close();
progressBar1.Value = progressBar1.Maximum;
progressBar1.Value = progressBar1.Minimum;
progressBar1.Hide();
progressBar1.Hide();
}
private void загрузитьГрафToolStripMenuItem
{
button3_Click(sender, e);
int[] x, y;
Point pnt = new Point();
OpenFileDialog o = new OpenFileDialog();
o.DefaultExt = ".xml";
o.Filter = "Графвформате *.xml|*.xml";
if (o.ShowDialog() != DialogResult.OK) return;
XmlTextReader r = new XmlTextReader(o.FileName);
while (r.Read() && (r.Name != "Структура"));
while (r.Read() && (r.Name != "Неориентированный_граф"));
numericUpDown1.Value = XmlConvert.ToInt32(r.
n = (int)numericUpDown1.Value;
x = new int[n];
y = new int[n];
for (short i = 0; i< n; i++)
{
while (r.Read() && (r.Name != "Строка_" + (i + 1))) ;
for (short j = 0; j < n; j++)
{
dataGridView1[j, i].Value
= XmlConvert.ToDouble(r.
}
}
while (r.Read() && (r.Name != "Остовый_лес")) ;
for (short i = 0; i< n; i++)
{
while (r.Read() && (r.Name != "Строка_" + (i + 1))) ;
for (short j = 0; j < n; j++)
{
dataGridView2[j, i].Value
= XmlConvert.ToDouble(r.
}
}
while (r.Read() && (r.Name != "Массив_координат")) ;
while (r.Read() && (r.Name != "Координаты_x")) ;
for (short i = 0; i< n; i++)
{
x[i] = XmlConvert.ToInt32(r.
}
while (r.Read() && (r.Name != "Координаты_y")) ;
for (short i = 0; i< n; i++)
{
y[i] = XmlConvert.ToInt32(r.
}
for (inti = 0; i< n; i++)
{
pnt.X = x[i];
pnt.Y = y[i];
koord.Add(pnt);
}
pictureBox1.Invalidate();
pictureBox2.Invalidate();
}
private void button4_Click(object sender, EventArgs e)
{
koord.Clear();
Random z1 = new Random();
Point x = new Point();
for (short i = 0; i< n; i++)
{
x.X = z1.Next(20, pictureBox1.ClientSize.Width - 20);
x.Y = z1.Next(20, pictureBox1.ClientSize.Height - 20);
koord.Add(x);
}
pictureBox1.Invalidate();
}
private void справкаToolStripMenuItem_
{
}
public void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (koord.Count != n)
return;
Point[] pnt = (Point[])koord.ToArray(typeof(

- Алгоритм Краскала
- Алгоритм метода простой итерации при решении систем нелинейных уравнений
- Алгоритмнің құрылым негіздері мен қолдану тәсілдері
- Алгоритм обмена секретным ключом Диффи-Хеллмана
- Алгоритм обработки данных с помощью метода однофакторного дисперсионного анализа (ANOVA) и критерия Н-Краскала-Уоллеса
- Алгоритм обратного распространения ошибки
- Алгоритм осмотра места происшествия
- «Алгоритмические языки и программирование»
- Алгоритмические языки и программирование
- Алгоритмические языки и программирование
- Алгоритмізація та програмування
- Алгоритмізація та програмування задачі обробки економічної інформації
- Алгоритм кодирования речевых сигналов GSM. Его алгоритм функционирования, параметры, область применения, показатели качества, сравнение с
- Алгоритм Кока-Янгера-Касами