Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
37
Добавлен:
22.05.2015
Размер:
361.47 Кб
Скачать

8.

A

B

C

D

E

F

G

A

0

3

1

5

10

5

6

B

3

0

5

3

1

8

6

C

1

5

0

1

5

1

2

D

5

3

1

0

3

3

3

E

10

1

5

3

0

4

5

F

5

8

1

3

4

0

1

G

6

6

2

3

5

1

0

9.

A

B

C

D

E

F

G

A

0

3

1

5

7

9

6

B

3

0

5

3

1

8

6

C

1

5

0

6

5

1

2

D

5

3

6

0

3

7

3

E

7

1

5

3

0

1

5

F

9

8

1

7

1

0

1

G

6

6

2

3

5

1

0

10.

A

B

C

D

E

F

G

A

0

4

1

5

7

5

6

B

4

0

5

3

2

8

9

C

1

5

0

1

5

1

2

D

5

3

1

0

3

3

8

E

7

2

5

3

0

1

5

F

5

8

1

3

1

0

1

G

6

9

2

8

5

1

0

3.2 Задания для вычисления с помощью программы:

Задан полный граф с длинами ребер. Построить для него граф наименьшей длины, используя известную среду программирования.

4. МЕТОДИЧЕСКИЕ УКАЗАНИЯ

Описание алгоритма Краскала на псевдокоде:

T <- пустое множкство;

VS <- пустое множество;

Построить очередь с приоритетами Q, содержащую все ребра из E;

for (v принадлежащего V) Добавить {v} к VS

while |VS|>1

{

Выбрать в Q ребро (v,w) наименьшей стоимости;

Удалить (v,w) из Q;

if v и w принадлежат различным множествам W1 и W2 из VS

{

Заменить W1 и W2 на объединение W1 и W2 в VS;

Добавить (v,w) к T;

}

}

    Реализуем алгоритм на языке C++. Для хранения ребер и их стоимостей воспользуемся бинарным деревом поиска, описание которого имеет вид:

typedef unsigned int SubInt;

typedef struct Uzel *Ref;

typedef struct Uzel

{

SubInt X; //Начало дуги.

SubInt Y; //Конец дуги

int Pay; //Стоимость дуги.

Ref Left; //Указатель на левого сына.

Ref Right;//Указатель на правого сына.

};

    Ясно, что в "самой левой" вершине дерева будет храниться дуга, обладающая наименьшей стоимостью, и поиск этой вершины может выглядеть, например, так:

UkUzel = Root; //Установили текущий указатель на корень дерева.

while (UkUzel->Left != NULL)

UkUzel = UkUzel->Left;

T1 = UkUzel->X; T2 = UkUzel->Y; //Получили ребро!

    Множество VS будем хранить в линейном однонаправленном списке с заглавным звеном, описание которого выглядит так:

typedef struct zveno *svqz;

typedef struct zveno

{

unsigned int Element[256]; // Множество из VS.

svqz Sled; // Указатель на узел.

zveno(); // Конструктор.

};

zveno::zveno()

//Обнуление элементов.

{

for(int k=0;k<256;Element[k++]=0);

}

    Тогда, например, фрагмент алгоритма:

if v и w принадлежат различным множествам W1 и W2 из VS

{

Заменить W1 и W2 на объединение W1 и W2 в VS;

Добавить (v,w) к T;

}

запишется на языке С++ так:

Res1 = Res2 = NULL;

Poisk (UkStr,T1,&Res1);

Poisk (UkStr,T2,&Res2);

if ( Res1!=Res2 )

{

for (int k=0;k<256;k++)

if ( Res1->Element[k]==1 || Res2->Element[k]==1 ) Res1->Element[k]=1;

Udalenie (&Res2,UkStr);

cout << "(" << T1 << " " << T2 << ") ";

}

    Пример. Построение графа наименьшей длины (алгоритм Краскала).

#include <iostream.h>

#define TRUE 1

#define FALSE 0

typedef int Boolean;

typedef unsigned int SubInt;

typedef struct Uzel *Ref;

typedef struct Uzel

{

SubInt X; //Начало дуги.

SubInt Y; //Конец дуги

int Pay; //Стоимость дуги.

Ref Left; //Указатель на левого сына.

Ref Right;//Указатель на правого сына.

};

typedef struct zveno *svqz;

typedef struct zveno

{

unsigned int Element[256];

svqz Sled;

zveno();

};

zveno::zveno()

{

for(int k=0;k<256;Element[k++]=0);

}

class Spisok

{

private:

Ref Root;

void Search (int, int, int, Ref *);

void Poisk (svqz, SubInt, svqz *);

void Postroenie (svqz *);

void Udalenie (svqz *, svqz);

public:

Spisok() { Root = NULL;} //Вначале дерево пусто.

void Reshenie();

void Postr();

};

void Spisok::Search (int A, int B, int C, Ref *p)

//Добавление вершины, содержащей поля A,B,C, в дерево *p.

{

if ( (*p) == NULL )

{

(*p) = new (Uzel); (**p).X = A; (**p).Y = B; (**p).Pay = C;

(**p).Left = (**p).Right = NULL;

}

else

if ( C<=(**p).Pay ) Search (A,B,C,&((**p).Left));

else

if ( C>(**p).Pay ) Search (A,B,C,&((**p).Right));

}

void Spisok::Postroenie (svqz *UkStr)

//Постpоение линейного однонапpавленного списка

//с заглавным звеном, содержащего вершины графа.

{

svqz UkZv;

int el;

(*UkStr) = new (zveno);

UkZv = (*UkStr); UkZv->Sled = NULL;

cout << "Вводите вершины графа: \n";

cin >> el;

while ( el!=0 )

{

UkZv->Sled = new (zveno); UkZv = UkZv->Sled;

UkZv->Element[el] = 1; UkZv->Sled = NULL;

cin >> el;

}

}

void Spisok::Postr()

//Постpоение деpева, содержащего все ребра графа.

{

int A,B,C;

cout << "Для каждого ребра вводите начальную, затем конечную\n";

cout << "вершины и стоимость ребра, их соединяющего:\n";

cin >> A >> B >> C;

while ( A!=0 )

{ Search (A,B,C,&Root);

cin >> A >> B >> C;

}

}

void Spisok::Poisk (svqz st, SubInt MENT, svqz *Res)

{

svqz q;

(*Res) = NULL; q = st->Sled;

while ( q != NULL && (*Res) == NULL )

{

if ( q->Element[MENT]==1 ) (*Res) = q;

else q = q->Sled;

}

}

void Spisok::Udalenie (svqz *zv, svqz UkStr)

//Удаление из однонапpавленного списка с заглавным звеном

//элемента, на который указывает указатель zv.

{

svqz Z; //"Стаpый" указатель.

svqz UkZv1; //"Hовый" указатель.

if ( (*zv)->Sled != NULL ) (**zv) = *((**zv).Sled);

else

{ Z = UkStr; UkZv1 = UkStr->Sled;

while (UkZv1 != (*zv))

{ Z = UkZv1; UkZv1 = UkZv1->Sled; }

Z->Sled = NULL; delete UkZv1;

}

}

void Spisok::Reshenie()

{

svqz UkStr; //Указатель на список.

Ref UkUzel; //Рабочий указатель на узел дерева.

Ref UkUzel1; //Рабочий указатель на узел дерева.

SubInt T1,T2;

svqz Res1,Res2;

//Построение первоначальных множеств вершин графа.

Postroenie (&UkStr);

cout <<"Ребра экономического дерева: ";

while ( UkStr->Sled->Sled != NULL )

{

UkUzel1 = Root; //"Отстающий" указатель.

UkUzel = Root->Left; //"Опережающий" указатель.

if ( UkUzel== NULL )

{ //Выбор в дереве ребра наименьшей стоимости и ...

T1 = Root->X; T2 = Root->Y;

//... удаление этого ребра из дерева.

Root = Root->Right; delete UkUzel1;

}

else

{ //Выбор в дереве ребра наименьшей длиныи и ...

while ( UkUzel->Left != NULL )

{

UkUzel1 = UkUzel1->Left;

UkUzel = UkUzel->Left;

}

T1 = UkUzel->X; T2 = UkUzel->Y;

//... удаление этого ребра из дерева.

UkUzel1->Left = UkUzel->Right;

delete UkUzel;

}

//Если v и w принадлежат различным

//множествам W1 и W2 из VS ...

Res1 = Res2 = NULL;

Poisk (UkStr,T1,&Res1);

Poisk (UkStr,T2,&Res2);

if ( Res1!=Res2 )

{

for (int k=0;k<256;k++)

if ( Res1->Element[k]==1 || Res2->Element[k]==1 )

Res1->Element[k]=1;

Udalenie (&Res2,UkStr);

cout << "(" << T1 << " " << T2 << ") ";

}

}

}

void main ()

{

Spisok Tree;

Tree.Postr();

Tree.Reshenie();

}

Алгоритм поиска графа наименьшей длины методом Краскала

5. СОДЕРЖАНИЕ ОТЧЕТА

  • наименование работы, постановку задачи;

  • выбранный вариант задания;

  • результаты решения задач без применения ЭВМ;

  • программу решения задачи (представляется в электронном виде);

  • результаты работы программы и их анализ.

6. КОНТРОЛЬНЫЕ ВОПРОСЫ

  1. Сформулируйте задачу о построении графа наименьшей длины на примере построения автомобильных дорог.

  2. Дайте определение дерева.

  3. Дайте определение ациклическому графу.

  4. Почему граф наименьшей длины всегда является деревом?

  5. Какое дерево называется экономическим?

  6. Опишите алгоритм построения графа наименьшей длины.

  7. Кем был предложен данный алгоритм?

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

  9. Каковы этапы алгоритма построения остова наименьшей стоимости? тождественен ли он алгоритму Краскала?

7. ОСНОВНАЯ ЛИТЕРАТУРА

  1. А. А. Зыков Основы теории графов – М., Наука, 1987. – 380, [1] с. кл.; 23 см.

  2. А. И. Белоусов Дискретная математика: Учеб. пособие для втузов/Белоусов А. И., Ткачев С. Б., Под ред. Зарубина В. С., Ирищенко А. П. – 3-е изд., стер. – М.: Изд-во МГТУ им. Баумана, 2004. – 743 с.

  3. О. П. Кузнецов, Г. М. Адельсон-Вельский «Дискретная математика для инженера». - М.: Энергоатомиздат, 1988 – 479, [1] с.: кл., 22 см.

  4. Горбатов В. А. Дискретная математика: Учеб. для втузов В. А. Горбатов. – М.АСТ; Астель, 2003 – 447с (Высшая школа)

ДОПОЛНИТЕЛЬНАЯ ЛИТЕРАТУРА

1. М. С. Спирина, П. А. Спирин, «Дискретная математика»

Издательство: Академия, 2009 г., 368 стр.

2.Н. И. Костюкова, «Графы и их применение. Комбинаторные алгоритмы для программистов»

Издательства: Интернет-университет информационных технологий, Бином. Лаборатория знаний, 2007 , 312 стр.

3. В. Ф. Пономарев «Дискретная математика для инженеров»

Издательство: Горячая Линия - Телеком, 2009 г. Мягкая обложка, 320 стр.

4. Ю. П. Шевелев, «Дискретная математика»

Издательство: Лань, 2008 г, 592стр.

17

Соседние файлы в папке дискретка