Алгоритмизация и программирование. Целочисленные алгоритмы. 11 класс

Содержание

Слайд 2

Алгоритмизация и программирование § 38. Целочисленные алгоритмы

Алгоритмизация и программирование

§ 38. Целочисленные алгоритмы

Слайд 3

Решето Эратосфена Эратосфен Киренский (Eratosthenes, Ερατοσθδνη) (ок. 275-194 до н.э.) Новая

Решето Эратосфена

Эратосфен Киренский (Eratosthenes, Ερατοσθδνη) (ок. 275-194 до н.э.)

Новая версия – решето

Аткина .

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Алгоритм:
начать с k = 2
«выколоть» все числа через k, начиная с 2·k
перейти к следующему «невыколотому» k
если k <= N , то перейти к шагу 2
напечатать все числа, оставшиеся «невыколотыми»

высокая скорость, количество операций

нужно хранить в памяти все числа от 1 до N

O((N·log N)·log log N )

2

3

k·k

k·k <= N

Слайд 4

Решето Эратосфена Задача. Вывести все простые числа от 2 до N.

Решето Эратосфена

Задача. Вывести все простые числа от 2 до N.

Объявление переменных:

цел

i, k, N = 100
логтаб A[2:N]

Сначала все невычеркнуты:

нц для i от 2 до N
A[i]:= да
кц

const N = 100;
var i, k: integer;
A: array[2..N]
of boolean;

for i:= 2 to N do
A[i]:= True;

Слайд 5

Решето Эратосфена Вычёркивание непростых: k:= 2 нц пока k*k если A[k]

Решето Эратосфена

Вычёркивание непростых:

k:= 2
нц пока k*k <= N
если A[k] то

i:= k*k
нц пока i <= N
A[i]:= нет
i:= i + k
кц
все
k:= k + 1
кц

k:= 2;
while k*k <= N do begin
if A[k] then begin
i:= k*k;
while i <= N do begin
A[i]:= False;
i:= i + k
end
end;
k:= k + 1
end;

Слайд 6

Решето Эратосфена Вывод результата: нц для i от 2 до N

Решето Эратосфена

Вывод результата:

нц для i от 2 до N
если A[i]

то
вывод i, нс
все
кц

for i:= 2 to N do
if A[i] then
writeln ( i );

Слайд 7

«Длинные» числа Ключи для шифрования: ≥ 256 битов. Целочисленные типы данных:

«Длинные» числа

Ключи для шифрования: ≥ 256 битов.
Целочисленные типы данных: ≤ 64

битов.

Длинное число – это число, которое не помещается в переменную одного из стандартных типов данных языка программирования.

«Длинная арифметика» – алгоритмы для работы с длинными числами.

Слайд 8

«Длинные» числа A = 12345678 нужно хранить длину числа неудобно вычислять

«Длинные» числа

A = 12345678

нужно хранить длину числа
неудобно вычислять (с младшего разряда!)
неэкономное

расходование памяти

Обратный порядок элементов:

Слайд 9

«Длинные» числа Упаковка элементов: 12345678 = 12·10002 + 345·10001 + 678·10000

«Длинные» числа

Упаковка элементов:

12345678 = 12·10002 + 345·10001 + 678·10000

система счисления с

основанием 1000!

от –231 = – 2 147 483 648 до 231 – 1 = 2 147 483 647.

longint:

должны помещаться все промежуточные результаты!

A = 12345678

Слайд 10

Вычисление факториала Задача 1. Вычислить точно значение факториала 100! = 1·2·3·…·99·100

Вычисление факториала

Задача 1. Вычислить точно значение факториала
100! = 1·2·3·…·99·100

1·2·3·…·99·100

< 100100

201 цифра

6 цифр в ячейке ⇒ 34 ячейки

цел N = 33
целтаб A[0:N]

const N = 33;
var A: array[0..N]
of longint;

Основной алгоритм:

[A]:= 1
нц для k от 2 до 100
[A]:= [A] * k
кц

длинное число

основание 1000000

Слайд 11

Вычисление факториала основание d = 1 000 000 [A] = 12345678901734567

Вычисление факториала

основание d = 1 000 000

[A] = 12345678901734567

734 567·3 = 2 203 701

*3

остаётся

в A[0]

r := перенос в A[1]

s:= A[0]*k
A[0]:= mod(s,d)
r:= div(s,d)

s:= A[0]*k;
A[0]:= s mod d;
r:= s div d;

s:= A[1]*k + r

Слайд 12

Вычисление факториала r:= 0 нц для i от 0 до N

Вычисление факториала

r:= 0
нц для i от 0 до N
s:= A[i]*k

+ r
A[i]:= mod(s,d)
r:= div(s,d)
кц

r:= 0;
for i:= 0 to N do begin
s:= A[i]*k + r;
A[i]:= s mod d;
r:= s div d
end;

Умножение «длинного» числа на k:

Вычисление 100!:

нц для k от 2 до 100
...
кц

for k:=2 to 100 do
begin
...
end;

Слайд 13

Вывод длинного числа [A] = 1000002000003 найти старший ненулевой разряд вывести

Вывод длинного числа

[A] = 1000002000003

найти старший ненулевой разряд
вывести этот разряд
вывести все

следующие разряды, добавляя лидирующие нули до 6 цифр

i:= N
нц пока A[i] = 0
i:= i - 1
кц

i:= N;
while A[i] = 0 do
i:= i - 1;

вывод A[i]

write( A[i] );

Слайд 14

Вывод длинного числа нц для k от i-1 до 0 шаг

Вывод длинного числа

нц для k от i-1 до 0 шаг -1

Write6(A[k])
кц

for k:=i-1 downto 0 do
Write6(A[k]);

Вывод остальных разрядов:

со старшего

Write6:

x = 12345

012345

x div 100000

x mod 100000

Слайд 15

Вывод длинного числа Вывод числа с лидирующими нулями: алг Write6 (цел

Вывод длинного числа

Вывод числа с лидирующими нулями:

алг Write6 (цел x)
нач
цел

M, xx
xx:= x
M:= 100000
нц пока M > 0
вывод div(xx, M)
xx:= mod(xx, M)
M:= div(M, 10)
кц
кон
Слайд 16

Вывод длинного числа Вывод числа с лидирующими нулями: procedure Write6(x: longint);

Вывод длинного числа

Вывод числа с лидирующими нулями:

procedure Write6(x: longint);
var M:

longint;
begin
M:= 100000;
while M > 0 do begin
write(x div M);
x:= x mod M;
M:= M div 10
end
end;
Слайд 17

Алгоритмизация и программирование § 39. Структуры (записи)

Алгоритмизация и программирование

§ 39. Структуры (записи)

Слайд 18

Зачем нужны структуры? Книги в библиотеках: автор название количество экземпляров …

Зачем нужны структуры?

Книги в библиотеках:

автор
название
количество экземпляров

символьные строки

целое число

Задачa: объединить разнотипные данные

в один блок.

Несколько массивов:

var authors: array[1..N] of string;
titles: array[1..N] of string;
count: array[1..N] of integer;
...

неудобно работать (сортировать и т.д.), ошибки

Слайд 19

Структуры (записи) Структура – это тип данных, который может включать в

Структуры (записи)

Структура – это тип данных, который может включать в себя

несколько полей – элементов разных типов (в том числе и другие структуры).

type
TBook = record
author: string[40];{ автор, строка }
title: string[80]; { название, строка}
count: integer { количество, целое }
end;

новый тип данных

структура (запись)

Слайд 20

Объявление структур const N = 100; var B: TBook; { одна

Объявление структур

const N = 100;
var B: TBook; { одна структура }

Books: array[1..N] of TBook; { массив }

writeln(sizeof(TBook)); { 124 }
writeln(sizeof(B)); { 124 }
writeln(sizeof(Books)); { 12400 }

type
TBook = record
author: string[40];
title: string[80];
count: integer
end;

2 байта (FreePascal)

40 + 1 (размер) байт

80 + 1 (размер) байт

Слайд 21

Обращение к полям структур B.author { поле author структуры B }

Обращение к полям структур

B.author { поле author структуры B }

Точечная нотация:

Books[5].count

{ поле count структуры
Books[5] }

writeln(sizeof(B.author)); { 41 }
writeln(sizeof(B.title)); { 81 }
writeln(sizeof(B.count)); { 2 }

read(B.author); { ввод полей }
read(B.title);
read(B.count);

writeln(B.author, ' ', { вывод }
B.title, '. ', B.count, ' шт.' );

Слайд 22

Обращение к полям структур B.author:= 'Пушкин А.С.'; B.title:= 'Полтава'; B.count:= 1;

Обращение к полям структур

B.author:= 'Пушкин А.С.';
B.title:= 'Полтава';
B.count:= 1;

p:= Pos(' ', B.author);
fam:=

Copy(B.author, 1, p-1); { фамилия }
B.count:= B.count – 1; { одну книгу взяли }
if B.count = 0 then
writeln('Этих книг больше нет!');

Присваивание:

Использование:

Слайд 23

Запись структур в файлы 'Пушкин А.С.';'Полтава';12 'Лермонтов М.Ю.';'Мцыри';8 Текстовые файлы: символ-разделитель

Запись структур в файлы

'Пушкин А.С.';'Полтава';12
'Лермонтов М.Ю.';'Мцыри';8

Текстовые файлы:

символ-разделитель

Типизированные файлы:

var F: file of

TBook;

Assign(F, 'books.dat');
Rewrite(F);
B.author:= 'Тургенев И.С.';
B.title:= 'Муму';
B.count:= 2;
write(F, B);
Close(F);

for i:=1 to N do
write(F, Books[i]);

только для TBook!

Слайд 24

Чтение структур из файла Assign(F, 'books.dat'); Reset(F); Read(F, B); writeln(B.author,', ',B.title,

Чтение структур из файла

Assign(F, 'books.dat');
Reset(F);
Read(F, B);
writeln(B.author,', ',B.title,
',

',B.count);
Close(F);

только для TBook!

for i:= 1 to N do { известное количество }
read(F, Books[i]);

i:= 0;
while not Eof(F) do begin { до конца файла }
i:= i + 1;
Read(F, Books[i])
end;

счётчик прочитанных структур

Слайд 25

Сортировка структур Ключ – фамилия автора: for i:=1 to N-1 do

Сортировка структур

Ключ – фамилия автора:

for i:=1 to N-1 do
for j:=N-1

downto i do
if Books[j].author > Books[j+1].author
then begin
B:= Books[j];
Books[j]:= Books[j+1];
Books[j+1]:= B
end;

структуры перемещаются в памяти

B:= Books[j];
Books[j]:= Books[j+1];
Books[j+1]:= B

var B: TBook;

Слайд 26

Указатели Указатель – это переменная, в которой можно сохранить адрес любой

Указатели

Указатель – это переменная, в которой можно сохранить адрес любой переменной

заданного типа.

type PBook = ^TBook;

pointer

указатель на переменную типа TBook

var P: PBook;

P:=@B;

P:=@Books[3];

P^.author ⇔ Books[3].author

Слайд 27

Сортировка по указателям var p: array[1..N] of PBook; for i:=1 to

Сортировка по указателям

var p: array[1..N] of PBook;

for i:=1 to N do


p[i]:= @Books[i];

Задача – переставить указатели:

Слайд 28

Сортировка по указателям for i:= 1 to N-1 do for j:=

Сортировка по указателям

for i:= 1 to N-1 do
for j:= N-1

downto i do
if p[j]^.author > p[j+1]^.author
then begin
p1:= p[j]; p[j]:= p[j+1];
p[j+1]:= p1
end;

var p1: PBook;

обращение к полям через указатели

Вывод результата:

for i:=1 to N do
writeln(p[i]^.author, '; ',
p[i]^.title, '; ',
p[i]^.count);

переставляем указатели!

Слайд 29

Алгоритмизация и программирование § 40. Множества 2-е издание

Алгоритмизация и программирование

§ 40. Множества

2-е издание

Слайд 30

Зачем нужны множества? Задача. Определить количество знаков препинания в символьной строке.

Зачем нужны множества?

Задача. Определить количество знаков препинания в символьной строке.

count:= 0;

for i:=1 to Length(s) do
if (s[i]='.') or (s[i]=',')
or (s[i]=';') or (s[i]=':')
or (s[i]='!') or (s[i]='?') then
count:= count + 1;

Использование множества:

if s[i] in ['.', ',', ';', ':', '!', '?'] then
count:= count + 1;

входит во

множество

['.', ',', ';', ':', '!', '?']

(s[i]='.') or (s[i]=',')
or (s[i]=';') or (s[i]=':')
or (s[i]='!') or (s[i]='?')

Слайд 31

Использование множеств if s[i] in ['0'.. '9'] then count:= count +

Использование множеств

if s[i] in ['0'.. '9'] then
count:= count +

1;

диапазон

if s[i] in ['a'..'z', '0'..'9',
'.', '-', '_'] then
{ символ правильный }

var digits: set of '0'..'9';

Переменная типа «множество»:

множество цифр

Слайд 32

Использование множеств Задача. Вывести все различные цифры, присутствующие в символьной строке

Использование множеств

Задача. Вывести все различные цифры, присутствующие в символьной строке s.

var

s: string;
i: integer;
c: char;
digits: set of '0'..'9';
begin
readln(s);
digits:=[]; { пустое множество }
for i:=1 to Length(s) do
if s[i] in ['0'..'9']
then
for c:='0' to '9' do
if c in digits then writeln(c)
end.

digits:= digits + [s[i]];

сложить два множества

вывод через перебор

Слайд 33

Использование множеств var cs: set of char; bs: set of byte;

Использование множеств

var cs: set of char;
bs: set of byte;

до 255

элементов

Имена для элементов множества:

type TFontStyles = (fsBold, fsItalic,
fsUnderline);

стили шрифта

жирный

курсив

подчёркивание

var fs: set of TFontStyles;

Операции с множеством:

fs:= [fsBold, fsItalic]; { присвоить значение}
fs:= fs + [fsUnderline]; { добавить элементы }
fs:= fs - [fsItalic]; { исключить элементы }

Слайд 34

Вывод множества на экран type TFontStyles = (fsBold, fsItalic, fsUnderline); var

Вывод множества на экран

type TFontStyles = (fsBold, fsItalic,
fsUnderline);
var style: TFontStyles;

fs:=

[fsBold, fsItalic];
for style:=fsBold to fsUnderline do
if style in fs then
write(1)
else write(0);

первый

последний

110

fsBold

fsItalic

fsUnderline

Слайд 35

Сравнение множеств Равенство/неравенство: if A = B then write('A = B');

Сравнение множеств

Равенство/неравенство:

if A = B then write('A = B'); { нет

}
if B = C then write('B = C'); { да }

var A, B, C: set of 0..9;
...
A:= [1,2,3,4]; B:= [2,3]; C:= [2,3]

if A <> B then write('A <> B'); { да }
if C <> B then write('C <> B'); { нет }

Включение одного в другое:

if A >= B then write('A >= B'); { да }
if C <= B then write('C <= B'); { да }

if A > B then write('A > B'); { да }
if C < B then write('C < B'); { нет }

Слайд 36

Множества в памяти Пустое множество: var digits: set of 0..9; digits:=

Множества в памяти

Пустое множество:

var digits: set of 0..9;

digits:= [];

Непустое множество:

digits:= [1,

3, 5, 7];

Пересечение множеств:

digits:= [1, 3, 5, 7] *
[2, 3, 4];

AND

логическое умножение

[3]

Слайд 37

[1, 2, 3, 4, 5, 7] Множества в памяти Объединение множеств:

[1, 2, 3, 4, 5, 7]

Множества в памяти

Объединение множеств:

digits:= [1, 3,

5, 7] +
[2, 3, 4];

OR

логическое сложение

Вычитание множеств:

digits:= [1, 3, 5, 7] -
[2, 3, 4];

[1, 5, 7]

Слайд 38

Алгоритмизация и программирование § 40. Динамические массивы

Алгоритмизация и программирование

§ 40. Динамические массивы

Слайд 39

Чем плох обычный массив? const N = 100; var A: array[1..N]

Чем плох обычный массив?

const N = 100;
var A: array[1..N] of integer;

статический

массив

память выделяется при трансляции
нужно заранее знать размер
изменить размер нельзя

Задача. В файле записаны фамилии (сколько – неизвестно!). Вывести их в другой файл в алфавитном порядке.

выделить заранее большой блок (с запасом)
выделять память во время работы программы (динамически!)

Слайд 40

Динамические структуры данных создавать новые объекты в памяти изменять их размер

Динамические структуры данных

создавать новые объекты в памяти
изменять их размер
удалять из памяти,

когда не нужны

… позволяют

Задача. Ввести с клавиатуры целое значение N, затем – N целых чисел, и вывести на экран эти числа в порядке возрастания.

{ прочитать данные из файла в массив }
{ отсортировать их по возрастанию }
{ вывести массив на экран }

Слайд 41

Динамические массивы (FreePascal) Объявление: var A: array of integer; размер не

Динамические массивы (FreePascal)

Объявление:

var A: array of integer;

размер не указан

Выделение памяти:

read(N);
SetLength(A, N);

установить

длину

[0.. N-1]

Чтение данных:

for i:=0 to N-1 do read(A[i]);

for i:=0 to High(A) do read(A[i]);

наибольший индекс

Слайд 42

Динамические массивы (FreePascal) Определение длины: writeln( Length(A) ); Освобождение памяти: SetLength(A,

Динамические массивы (FreePascal)

Определение длины:

writeln( Length(A) );

Освобождение памяти:

SetLength(A, 0);

Динамические матрицы:

var A: array

of array of integer;

SetLength(A, 4, 3);

writeln( High(A) );

3

writeln( High(A[0]) );

2

Слайд 43

Динамические массивы (FreePascal) В подпрограммах: procedure printArray(X: array of integer); begin

Динамические массивы (FreePascal)

В подпрограммах:

procedure printArray(X: array of integer);
begin
for i:= 0

to High(X) do
write(X[i], ' ')
end;
Слайд 44

Расширение массива Задача. С клавиатуры вводятся натуральные числа, ввод заканчивается числом

Расширение массива

Задача. С клавиатуры вводятся натуральные числа, ввод заканчивается числом 0.

Нужно вывести на экран эти числа в порядке возрастания.

Расширение по 1 элементу:

read(x);
while x <> 0 do begin
SetLength(A, Length(A)+1);
A[High(A)]:= x;
read(x)
end;

Слайд 45

Расширение массива Расширение по 10 элементов: N:= 0; { счётчик элементов

Расширение массива

Расширение по 10 элементов:

N:= 0; { счётчик элементов }
read(x);
while x

<> 0 do begin
if N > High(A) then
SetLength(A, Length(A)+10);
A[N]:= x;
N:= N + 1;
read(x)
end;
Слайд 46

Как это работает? Эксперимент: SetLength(A, 100); write(sizeof(A)); write(100*sizeof(integer)); 4 200 размер

Как это работает?

Эксперимент:

SetLength(A, 100);
write(sizeof(A));
write(100*sizeof(integer));

4

200

размер массива

type TArray = record
data: array of

integer;
size: integer
end;
Слайд 47

Как это работает? var A: array of array of integer; SetLength(A,

Как это работает?

var A: array of array of integer;

SetLength(A, 10);

выделить массив

указателей

for i:=0 to High(A) do
SetLength(A[i], i+1);

Строки разной длины:

writeln(Length(A[0])); { 1 }
writeln(Length(A[9])); { 10 }

Слайд 48

Алгоритмизация и программирование § 41. Списки

Алгоритмизация и программирование

§ 41. Списки

Слайд 49

Зачем нужны списки? Задача. В файле находится список слов, среди которых

Зачем нужны списки?

Задача. В файле находится список слов, среди которых есть

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

Список – это упорядоченный набор элементов одного типа, для которого введены операции вставки (включения) и удаления (исключения).

Слайд 50

Алгоритм (псевдокод) нц пока есть слова в файле прочитать очередное слово

Алгоритм (псевдокод)

нц пока есть слова в файле
прочитать очередное слово

если оно есть в списке то
увеличить на 1 счётчик для этого слова
иначе
добавить слово в список
записать 1 в счетчик слова
все
кц
Слайд 51

Хранение данных type TPair = record word: string; { слово }

Хранение данных

type
TPair = record
word: string; { слово }

count: integer { счётчик }
end;

Пара «слово-счётчик»:

type
TWordList = record
data: array of TPair;
size: integer
end;

Список таких пар:

динамический массив

количество слов в списке

Слайд 52

Хранение данных var L: TWordList; Переменная-список: SetLength(L.data, 0); L.size:= 0; Начальные

Хранение данных

var L: TWordList;

Переменная-список:

SetLength(L.data, 0);
L.size:= 0;

Начальные значения:

Вывод результата:

Assign(F, 'output.dat');
Rewrite(F);
for p:=0 to

L.size-1 do
writeln(F, L.data[p].word, ': ',
L.data[p].count);
Close(F);

автомат: 1
ананас: 12
...

Слайд 53

Основной цикл while not Eof(F) { пока не конец файла }

Основной цикл

while not Eof(F) { пока не конец файла }
do

begin
readln(F, s); { читаем слово }
p:= Find(L, s); { ищем его в словаре}
if p >= 0 then { если нашли... }
Inc(L.data[p].count)
{ ...увеличить счётчик }
else begin { иначе... }
p:= FindPlace(L, s); { найти место }
InsertWord(L, p, s); { вставить в список }
end
end;
Слайд 54

Поиск слова function Find(L: TWordList; word: string): integer; var i: integer;

Поиск слова

function Find(L: TWordList;
word: string): integer;
var i: integer;
begin
Find:=

-1;
for i:=0 to L.size-1 do
if L.data[i].word = word then begin
Find:= i;
break
end
end;

вернуть -1, если нет в списке

вернуть номер элемента в списке

выйти из цикла

Слайд 55

Поиск места вставки function FindPlace(L: TWordList; word: string): integer; var i,

Поиск места вставки

function FindPlace(L: TWordList;
word: string): integer;
var i, p:

integer;
begin
p:= -1;
for i:=0 to L.size-1 do
if L.data[i].word > word then begin
p:= i;
break
end;
if p < 0 then p:= L.size;
FindPlace:= p
end;

-1: не найдено

запомнить номер

если не найдено, вставить в конец

первое слово «больше» заданного

Слайд 56

Вставка слова дерево for i:=L.size-1 downto k+1 do L.data[i]:= L.data[i-1]; Сдвиг вниз: с последнего

Вставка слова

дерево

for i:=L.size-1 downto k+1 do
L.data[i]:= L.data[i-1];

Сдвиг вниз:

с последнего

Слайд 57

Вставка слова procedure InsertWord(var L: TWordList; k: integer; word: string); var

Вставка слова

procedure InsertWord(var L: TWordList;
k: integer;
word: string);
var

i: integer;
begin
IncSize(L);
for i:=L.size-1 downto k+1 do
L.data[i]:= L.data[i-1];
L.data[k].word:= word; { записать слово }
L.data[k].count:= 1 { встретилось 1 раз }
end;

список меняется

увеличить размер, если нужно

сдвиг вниз

Слайд 58

Расширение списка procedure IncSize (var L: TWordList); begin Inc(L.size); if L.size

Расширение списка

procedure IncSize (var L: TWordList);
begin
Inc(L.size);
if L.size > Length(L.data)

then
SetLength(L.data, Length(L.data) + 10)
end;

список меняется

если новый размер больше размера массива

добавить 10 элементов

Слайд 59

Вся программа program AlphaList; { объявления типов TPair и TWordList }

Вся программа

program AlphaList;
{ объявления типов TPair и TWordList }
var F:

text;
w: string;
L: TWordList;
p: integer;
{ процедуры и функции }
begin
SetLength(L.data, 0);
L.size:= 0;
Assign(F, 'input.dat');
Reset(F);
{ основной цикл: составление списка слов }
Close(F);
{ вывод результата в файл output.dat }
end.
Слайд 60

Модули program AlphaList; { процедура 1 } { процедура 2 }

Модули

program AlphaList;
{ процедура 1 }
{ процедура 2 }

{ процедура 3 }
{ процедура 4 }
{ ...}
{ процедура N-1 }
{ процедура N }
begin
{ программа }
end.

program AlphaList;
uses WordList;
begin
{ программа }
end.

unit WordList;
{ процедура 1 }
{ процедура 2 }
{ процедура 3 }
{ процедура 4 }
{ ...}
{ процедура N-1 }
{ процедура N }
end.

проще разбираться («разделяй и властвуй»)
модуль пишет другой программист

Слайд 61

Структура модуля unit WordList; interface … implementation … end. «интерфейс» –

Структура модуля

unit WordList;
interface

implementation

end.

«интерфейс» – общедоступная информация:
объявление типов данных
объявления процедур

и функций

«реализация» – внутренняя информация модуля:
код процедур и функций
внутренние данные

Слайд 62

Модуль WordList unit WordList; interface { объявления типов TPair и TWordList

Модуль WordList

unit WordList;
interface
{ объявления типов TPair и TWordList }
function

Find(L: TWordList;
word: string): integer;
function FindPlace(L: TWordList;
word: string): integer;
procedure InsertWord(var L: TWordList;
k: integer; word: string);

implementation
{ код процедур и функций }
end.

Слайд 63

Подключение модуля program AlphaList; uses WordList; { подключение модуля } var

Подключение модуля

program AlphaList;
uses WordList;  { подключение модуля }
var F: text;
s:

string;
L: TWordList;
p: integer;
begin
{ тело основной программы } 
end.

тип известен из интерфейса модуля

можно использовать все процедуры, объявленные в интерфейсе модуля

Слайд 64

Связные списки узлы могут размещаться в разных местах в памяти только

Связные списки

узлы могут размещаться в разных местах в памяти

только последовательный доступ

Рекурсивное

определение:

пустой список – это список
список – это узел и связанный с ним список

конец списка

Слайд 65

Связные списки Head Циклический список: Двусвязный список: Head Tail «хвост» обход

Связные списки

Head

Циклический список:

Двусвязный список:

Head

Tail

«хвост»

обход в двух направлениях

сложнее вставка и удаление

Слайд 66

Связные списки: структуры данных Односвязный список: Двусвязный список: type PNode =

Связные списки: структуры данных

Односвязный список:

Двусвязный список:

type
PNode = ^TNode;
TNode

= record
data: integer;
next: PNode
end;

type
PNode = ^TNode;
TNode = record
data: integer;
next: PNode
end;

prev,

ссылка на следующий узел

указатель

ссылки на предыдущий (previous) и следующий узлы

Слайд 67

Алгоритмизация и программирование § 42. Стек, дек, очередь

Алгоритмизация и программирование

§ 42. Стек, дек, очередь

Слайд 68

Что такое стек? Стек (англ. stack – стопка) – это линейный

Что такое стек?

Стек (англ. stack – стопка) – это линейный список,

в котором элементы добавляются и удаляются только с одного конца («последним пришел – первым ушел»).

LIFO = Last In – First Out.

Системный стек:

адреса возврата из подпрограмм
передача аргументов подпрограмм
хранение локальных переменных

Слайд 69

Реверс массива Задача. В файле записаны целые числа. Нужно вывести их

Реверс массива

Задача. В файле записаны целые числа. Нужно вывести их в

другой файл в обратном порядке.

нц пока файл не пуст
прочитать x
добавить x в стек
кц

нц пока стек не пуст
вытолкнуть число из стека в x
записать x в файл
кц

1

2

3

4

5

5

4

3

2

1

Слайд 70

Использование динамического массива type TStack = record data: array of integer;

Использование динамического массива

type TStack = record
data: array of integer;
size:

integer
end;

procedure Push(var S: TStack; x: integer);
begin
if S.size > High(S.data) then
SetLength(S.data, Length(S.data) + 10);
S.data[S.size]:= x;
S.size:= S.size + 1
end;

изменяется

«Втолкнуть» x в стек:

Слайд 71

Использование динамического массива function Pop(var S:TStack): integer; begin S.size:= S.size-1; Pop:=

Использование динамического массива

function Pop(var S:TStack): integer;
begin
S.size:= S.size-1;
Pop:= S.data[S.size]
end;

изменяется

procedure InitStack(var

S: TStack);
begin
SetLength(S.data, 0);
S.size:= 0
end;

«Вытолкнуть» из стека в x :

Инициализация стека :

Слайд 72

Использование динамического массива InitStack(S); while not Eof(F) do begin read(F, x);

Использование динамического массива

InitStack(S);
while not Eof(F) do begin
read(F, x);
Push(S, x)
end;

Заполнение

стека:

for i:=0 to S.size-1 do begin
x:= Pop(S);
writeln(F, x)
end;

Вывод результата в файл:

var F: text;

Слайд 73

Вычисление арифметических выражений (5+15)/(4+7-1) инфиксная форма (знак операции между данными) первой

Вычисление арифметических выражений

(5+15)/(4+7-1)

инфиксная форма (знак операции между данными)

первой стоит последняя

операция (вычисляем с конца)

1920 (Я. Лукашевич): префиксная форма
(знак операции перед данными)

/ + 5 15 - + 4 7 1

/ 20 - + 4 7 1

/ 20 - 11 1

/ 20 10

2

не нужны скобки

Слайд 74

Вычисление арифметических выражений (5+15)/(4+7-1) 1950-е: постфиксная форма (знак операции после данных)

Вычисление арифметических выражений

(5+15)/(4+7-1)

1950-е: постфиксная форма
(знак операции после данных)

не нужны

скобки
вычисляем с начала

5 15 + 4 7 + 1 - /

20 4 7 + 1 - /

20 11 1 - /

20 10 /

2

Слайд 75

Использование стека 5 15 + 4 7 + 1 - /

Использование стека

5

15

+

4

7

+

1

-

/

5 15 + 4 7 + 1 - /

если число

– «втолкнуть» в стек
если операция – выполнить с верхними элементами стека
Слайд 76

Скобочные выражения Задача. Вводится символьная строка, в которой записано некоторое (арифметическое)

Скобочные выражения

Задача. Вводится символьная строка, в которой записано некоторое (арифметическое) выражение,

использующее скобки трёх типов: ( ), [ ] и { }. Проверить, правильное ли расставлены скобки.

()[{()[]}]

[()

)(

[()}

([)]

Для одного типа скобок:

( ) ( ( ) ( ( ) ) )

счётчик 0

1

0

1

2

1

2

3

2

1

0

счётчик всегда ≥ 0
в конце счётчик = 0

({[)}]

Слайд 77

Скобочные выражения (стек) когда встретили закрывающую скобку, на вершине стека лежит

Скобочные выражения (стек)

когда встретили закрывающую скобку, на вершине стека лежит соответствующая

открывающая
в конце работы стек пуст

если открывающая скобка – «втолкнуть» в стек
если закрывающая скобка – снять парную со стека

Слайд 78

Скобочные выражения (стек) type TStack = record data: array of char;

Скобочные выражения (стек)

type TStack = record
data: array of char;
size:

integer
end;

Модель стека:

Cтек пуст:

function isEmpty(S: TStack): boolean;
begin
isEmpty:= (S.size = 0)
end;

Слайд 79

Скобочные выражения (стек) const L = '([{'; { открывающие скобки }

Скобочные выражения (стек)

const L = '([{'; { открывающие скобки }
R

= ')]}'; { закрывающие скобки }
var S: TStack;
p, i: integer;
str: string; { рабочая строка }
err: boolean; { признак ошибки }
c: char;

Константы и переменные:

Вывод результата:

if not err then
writeln('Выражение правильное.')
else writeln('Выражение неправильное.');

Слайд 80

Скобочные выражения (стек) for i:=1 to Length(str) do begin p:= Pos(str[i],

Скобочные выражения (стек)

for i:=1 to Length(str) do begin
p:= Pos(str[i], L);

if p > 0 then Push(S, str[i]);
p:= Pos(str[i], R);
if p > 0 then begin
if isEmpty(S) then err:= True
else begin
c:= Pop(S);
if p <> Pos(c,L) then err:= True
end;
if err then break
end
end;

открывающую скобку в стек

если закрывающая скобка…

если не та скобка…

Слайд 81

Что такое очередь? Очередь – это линейный список, для которого введены

Что такое очередь?

Очередь – это линейный список, для которого введены две

операции:
• добавление элемента в конец
• удаление первого элемента

FIFO = Fist In – First Out.

Применение:

очереди сообщений в операционных системах
очереди запросов ввода и вывода
очереди пакетов данных в маршрутизаторах

Слайд 82

Заливка области Задача. Рисунок задан в виде матрицы A, в которой

Заливка области

Задача. Рисунок задан в виде матрицы A, в которой элемент

A[y,x] определяет цвет пикселя на пересечении строки y и столбца x. Перекрасить в цвет 2 одноцветную область, начиная с пикселя (x0,y0).

(2,1)

Слайд 83

Заливка: использование очереди добавить в очередь точку (x0,y0) запомнить цвет начальной

Заливка: использование очереди

добавить в очередь точку (x0,y0)
запомнить цвет начальной точки
нц пока

очередь не пуста
взять из очереди точку (x,y)
если A[y,x] = цвету начальной точки то
A[y,x]:= 2;
добавить в очередь точку (x-1,y)
добавить в очередь точку (x+1,y)
добавить в очередь точку (x,y-1)
добавить в очередь точку (x,y+1)
все
кц
Слайд 84

Очередь (динамический массив) type TPoint = record x, y: integer end;

Очередь (динамический массив)

type TPoint = record
x, y: integer
end;
TQueue

= record
data: array of TPoint;
size: integer
end;

function Point(x, y: integer): TPoint;
begin
Point.x:= x;
Point.y:= y
end;

Построение структуры «точка»:

Слайд 85

Очередь (динамический массив) Добавить точку в очередь: procedure Put(var Q: TQueue;

Очередь (динамический массив)

Добавить точку в очередь:

procedure Put(var Q: TQueue; pt: TPoint);
begin

if Q.size > High(Q.data) then
SetLength(Q.data,
Length(Q.data) + 10);
Q.data[Q.size]:= pt;
Q.size:= Q.size + 1;
end;

расширить, если нужно

4

5

Слайд 86

Очередь (динамический массив) Получить первую точку в очереди: function Get(var Q:TQueue):

Очередь (динамический массив)

Получить первую точку в очереди:

function Get(var Q:TQueue): TPoint;
var i:

integer;
begin
Get:= Q.data[0];
Q.size:= Q.size - 1;
for i:=0 to Q.Size - 1 do
Q.data[i]:= Q.data[i+1];
end;

уменьшить размер

продвинуть оставшиеся элементы

2

4

3

4

5

1

Слайд 87

Заливка const XMAX = 5; YMAX = 5; NEW_COLOR = 2;

Заливка

const XMAX = 5; YMAX = 5;
NEW_COLOR = 2;
var Q:

TQueue;
x0, y0, color: integer;
A: array[1..YMAX,1..XMAX] of integer;
pt: TPoint;

{ заполнить матрицу A }
x0:= 2; y0:= 1; { начать заливку отсюда }
color:= A[y0,x0]; { цвет начальной точки }
Put(Q, Point(x0,y0));

Константы и переменные:

Начало программы:

Слайд 88

Заливка (основной цикл) while not isEmpty(Q) do begin pt:= Get(Q); {

Заливка (основной цикл)

while not isEmpty(Q) do begin
pt:= Get(Q); { взять

точку из очереди }
if A[pt.y, pt.x] = color then begin
A[pt.y, pt.x]:= NEW_COLOR;
if pt.x > 1 then
Put(Q, Point(pt.x-1, pt.y));
if pt.x < XMAX then
Put(Q, Point(pt.x+1, pt.y));
if pt.y > 1 then
Put(Q, Point(pt.x, pt.y-1));
if pt.y < YMAX then
Put(Q, Point(pt.x, pt.y+1))
end
end;

пока очередь не пуста

Слайд 89

Очередь: статический массив нужно знать размер не двигаем элементы голова хвост Удаление элемента: Добавление элемента:

Очередь: статический массив

нужно знать размер

не двигаем элементы

голова

хвост

Удаление элемента:

Добавление элемента:

Слайд 90

Очередь: статический массив Замыкание в кольцо: Очередь заполнена: Очередь пуста:

Очередь: статический массив

Замыкание в кольцо:

Очередь заполнена:

Очередь пуста:

Слайд 91

Что такое дек? Дек – это линейный список, в котором можно

Что такое дек?

Дек – это линейный список, в котором можно добавлять

и удалять элементы как с одного, так и с другого конца.

Моделирование:

статический массив (кольцо)
динамический массив
связный список

Слайд 92

Алгоритмизация и программирование § 43. Деревья

Алгоритмизация и программирование

§ 43. Деревья

Слайд 93

Что такое дерево? «Сыновья» А: B, C. «Родитель» B: A. «Потомки»

Что такое дерево?

«Сыновья» А: B, C.

«Родитель» B: A.

«Потомки» А: B, C,

D, E, F, G.

«Предки» F: A, C.

Корень – узел, не имеющий предков (A).

Лист – узел, не имеющий потомков (D, E, F, G).

Слайд 94

Рекурсивные определения пустая структура – это дерево дерево – это корень

Рекурсивные определения

пустая структура – это дерево
дерево – это корень и несколько

связанных с ним отдельных (не связанных между собой) деревьев

Двоичное (бинарное) дерево:

пустая структура – это двоичное дерево
двоичное дерево – это корень и два связанных с ним отдельных двоичных дерева («левое» и «правое» поддеревья)

Применение:

поиск в большом массиве неменяющихся данных
сортировка данных
вычисление арифметических выражений
оптимальное сжатие данных (метод Хаффмана)

Слайд 95

Деревья поиска Ключ – это значение, связанное с узлом дерева, по

Деревья поиска

Ключ – это значение, связанное с узлом дерева, по которому

выполняется поиск.

слева от узла – узлы с меньшими или равными ключами
справа от узла – узлы с большими или равными ключами

O(log N)

Двоичный поиск O(log N)

Линейный поиск O(N)

Слайд 96

Обход дерева Обойти дерево ⇔ «посетить» все узлы по одному разу.

Обход дерева

Обойти дерево ⇔ «посетить» все узлы по одному разу.

список узлов

КЛП – «корень-левый-правый» (в прямом порядке):

посетить корень
обойти левое поддерево
обойти правое поддерево

ЛКП – «левый-корень-правый» (симметричный):

посетить корень
обойти левое поддерево
обойти правое поддерево

ЛПК – «левый-правый-корень» (в обратном порядке):

посетить корень
обойти левое поддерево
обойти правое поддерево

Слайд 97

Обход дерева ЛПК: КЛП: ЛКП: * + 1 4 – 9

Обход дерева

ЛПК:

КЛП:

ЛКП:

* + 1 4 – 9 5

1 + 4 *

9 - 5

1 4 + 9 5 - *

префиксная форма

инфиксная форма

постфиксная форма

Обход «в ширину»: «сыновья», потом «внуки», …

* + - 1 4 9 5

«в глубину»

Слайд 98

Обход КЛП – обход «в глубину» записать в стек корень дерева

Обход КЛП – обход «в глубину»

записать в стек корень дерева
нц пока

стек не пуст
V:= выбрать узел с вершины стека
посетить узел V
если у узла V есть правый сын то
добавить в стек правого сына V
все
если у узла V есть левый сын то
добавить в стек левого сына V
все
кц
Слайд 99

Обход КЛП – обход «в глубину» * + 1 4 – 9 5

Обход КЛП – обход «в глубину»

*

+

1

4


9

5

Слайд 100

Обход «в ширину» записать в очередь корень дерева нц пока очередь

Обход «в ширину»

записать в очередь корень дерева
нц пока очередь не пуста

V:= выбрать узел из очереди
посетить узел V
если у узла V есть левый сын то
добавить в очередь левого сына V
все
если у узла V есть правый сын то
добавить в очередь правого сына V
все
кц
Слайд 101

Обход «в ширину» (1+4)*(9-5) * + - 1 4 9 5 голова очереди

Обход «в ширину»

(1+4)*(9-5)

*

+

-

1

4

9

5

голова очереди

Слайд 102

Вычисление арифметических выражений 40–2*3–4*5 В корень дерева нужно поместить последнюю из операций с наименьшим приоритетом.

Вычисление арифметических выражений

40–2*3–4*5

В корень дерева нужно поместить последнюю из операций с

наименьшим приоритетом.
Слайд 103

Вычисление арифметических выражений найти последнюю выполняемую операцию если операций нет то

Вычисление арифметических выражений

найти последнюю выполняемую операцию
если операций нет то
создать узел-лист

выход
все
поместить операцию в корень дерева
построить левое поддерево
построить правое поддерево

построить левое поддерево
построить правое поддерево

Построение дерева:

Слайд 104

Вычисление арифметических выражений n1:= значение левого поддерева n2:= значение правого поддерева

Вычисление арифметических выражений

n1:= значение левого поддерева
n2:= значение правого поддерева
результат:= операция(n1, n2)


значение левого поддерева
значение правого поддерева

Вычисление по дереву:

Слайд 105

Использование связанных структур Дерево – нелинейная структура ⇒ динамический массив неудобен!

Использование связанных структур

Дерево – нелинейная структура ⇒ динамический массив неудобен!

type
PNode

= ^TNode; { указатель на узел }
TNode = record { узел дерева }
data: string[20];
left, right: PNode { ссылки на сыновей }
end;

ссылка вперёд

Слайд 106

Работа с памятью Выделить память для узла: var p: PNode; {

Работа с памятью

Выделить память для узла:

var p: PNode; { указатель на

узел }

New(p);

Обращение к новому узлу (по указателю):

p^.data:= s;
p^.left:= nil;
p^.right:= nil;

Освобождение памяти:

Dispose(p);

Слайд 107

Основная программа var T: PNode; { ссылка на дерево } s:

Основная программа

var T: PNode; { ссылка на дерево }
s: string;

{ строка с выражением }
{ процедуры и функции }
begin
readln(s);
T:= Tree(s); { построить дерево }
writeln('Результат: ',
Calc(T)); { вычисление }
end.
Слайд 108

Построение дерева function Tree(s: string): PNode; var k: integer; begin New(Tree);

Построение дерева

function Tree(s: string): PNode;
var k: integer;
begin
New(Tree); { выделить память

}
k:= LastOp(s); { вернет 0, если нет операции }
if k = 0 then begin { создать лист }
Tree^.data:= s;
Tree^.left:= nil;
Tree^.right:= nil
end
else begin { создать узел-операцию }
Tree^.data:= s[k];
Tree^.left:= Tree(Copy(s,1,k-1));
Tree^.right:= Tree(Copy(s,k+1,Length(s)-k))
end
end;

вернёт адрес нового дерева

Tree(Copy(s,1,k-1));
Tree(Copy(s,k+1,Length(s)-k))

Слайд 109

Вычисление по дереву function Calc(Tree: PNode): integer; var n1, n2, res:

Вычисление по дереву

function Calc(Tree: PNode): integer;
var n1, n2, res: integer;
begin
if

Tree^.left = nil then
Val(Tree^.data, Calc, res)
else begin
n1:= Calc(Tree^.left);
n2:= Calc(Tree^.right);
case Tree^.data[1] of
'+': Calc:= n1 + n2;
'-': Calc:= n1 - n2;
'*': Calc:= n1 * n2;
'/': Calc:= n1 div n2;
else Calc:= MaxInt
end
end
end;

Calc(Tree^.left);
Calc(Tree^.right);

Слайд 110

Приоритет операции function Priority(op: char): integer; begin case op of '+','-':

Приоритет операции

function Priority(op: char): integer;
begin
case op of
'+','-': Priority:= 1;

'*','/': Priority:= 2
else Priority:= 100
end
end;
Слайд 111

Последняя выполняемая операция function LastOp(s: string): integer; var i, minPrt: integer;

Последняя выполняемая операция

function LastOp(s: string): integer;
var i, minPrt: integer;
begin
minPrt:= 50;

{ любое между 2 и 100 }
LastOp:= 0; { если нет операции }
for i:=1 to Length(s) do
if Priority(s[i]) <= minPrt then begin
minPrt:= Priority(s[i]);
LastOp:= i
end
end;

<=

вернёт номер символа

Слайд 112

Двоичное дерево в массиве ? ?

Двоичное дерево в массиве

?

?

Слайд 113

Алгоритмизация и программирование § 44. Графы

Алгоритмизация и программирование

§ 44. Графы

Слайд 114

Что такое граф? Граф – это набор вершин и связей между

Что такое граф?

Граф – это набор вершин и связей между

ними (рёбер).

петля

Матрица смежности:

Список смежности:

( A(B, C), B(A, C, D), C(A, B, С, D), D(B, C) )

Слайд 115

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

Связность графа

Связный граф – это граф, между любыми вершинами которого

существует путь.
Слайд 116

Дерево – это граф? дерево ABC ABDC BCD CCC… Дерево –

Дерево – это граф?

дерево

ABC ABDC
BCD CCC…

Дерево – это связный граф без циклов

(замкнутых путей).
Слайд 117

Взвешенные графы Весовая матрица: вес ребра

Взвешенные графы

Весовая матрица:

вес ребра

Слайд 118

Ориентированные графы (орграфы) Рёбра имеют направление (начало и конец), рёбра называю дугами.

Ориентированные графы (орграфы)

Рёбра имеют направление (начало и конец), рёбра называю дугами.

Слайд 119

Жадные алгоритмы Жадный алгоритм – это многошаговый алгоритм, в котором на

Жадные алгоритмы

Жадный алгоритм – это многошаговый алгоритм, в котором на каждом

шаге принимается решение, лучшее в данный момент.

Задача. Найти кратчайший маршрут из А в F.

Слайд 120

Жадные алгоритмы Задача. Найти кратчайший маршрут из А в F.

Жадные алгоритмы

Задача. Найти кратчайший маршрут из А в F.

Слайд 121

Задача Прима-Крускала Задача. Между какими городами нужно проложить линии связи, чтобы

Задача Прима-Крускала

Задача. Между какими городами нужно проложить линии связи, чтобы все

города были связаны в одну систему и общая длина линий связи была наименьшей? (минимальное остовное дерево)

Алгоритм Крускала:

начальное дерево – пустое
на каждом шаге добавляется ребро минимального веса, которое ещё не входит в дерево и не приводит к появлению цикла

Слайд 122

Раскраска вершин 4 B 2 1 2 9 7 8 1

Раскраска вершин

4

B

2

1

2

9

7

8

1

3

D

E

F

A

C

ищем ребро минимальной длины среди всех рёбер, концы которых окрашены

в разные цвета;
найденное ребро (iMin,jMin) добавляется в список выбранных, и все вершины, имеющие цвет col[jMin], перекрашиваются в цвет col[iMin].

Сделать N-1 раз:

for i:=1 to N do col[i]:= i;

каждой вершине свой цвет

Слайд 123

Раскраска вершин const N = 6; var { весовая матрица }

Раскраска вершин

const N = 6;
var { весовая матрица }
W: array[1..N,1..N]

of integer;
{ цвета вершин }
col: array[1..N] of integer;
{ номера вершин для выбранных ребер }
ostov: array[1..N-1,1..2] of integer;
i, j, k, iMin, jMin, min, c: integer;

Данные:

Вывод результата:

for i:=1 to N-1 do
writeln('(', ostov[i,1], ',',
ostov[i,2], ')');

Слайд 124

Раскраска вершин for k:= 1 to N-1 do begin { поиск

Раскраска вершин

for k:= 1 to N-1 do begin
{ поиск ребра

с минимальным весом }
min:= MaxInt;
for i:= 1 to N do
for j:= 1 to N do
if (col[i] <> col[j]) and
(W[i,j] < min) then begin
iMin:= i; jMin:= j; min:= W[i,j]
end;
ostov[k,1]:= iMin; { добавление ребра }
ostov[k,2]:= jMin;
c:= col[jMin];
for i:= 1 to N do { перекрашивание вершин }
if col[i] = c then
col[i]:= col[iMin]
end;
Слайд 125

Кратчайший маршрут Алгоритм Дейкстры (1960): кратчайшее расстояние откуда ехать ближайшая от A невыбранная вершина

Кратчайший маршрут

Алгоритм Дейкстры (1960):

кратчайшее расстояние

откуда ехать

ближайшая от A невыбранная вершина

Слайд 126

Кратчайший маршрут Алгоритм Дейкстры (1960): кратчайшее расстояние откуда ехать W[x,z] +

Кратчайший маршрут

Алгоритм Дейкстры (1960):

кратчайшее расстояние

откуда ехать

W[x,z] + W[z,y] < W[x,y]

может быть

так, что

9

B

Слайд 127

Кратчайший маршрут Алгоритм Дейкстры (1960): кратчайшее расстояние откуда ехать W[x,z] +

Кратчайший маршрут

Алгоритм Дейкстры (1960):

кратчайшее расстояние

откуда ехать

W[x,z] + W[z,y] < W[x,y]

может быть

так, что

5

C

Слайд 128

Кратчайший маршрут Алгоритм Дейкстры (1960): кратчайшее расстояние откуда ехать 7 E 8 E

Кратчайший маршрут

Алгоритм Дейкстры (1960):

кратчайшее расстояние

откуда ехать

7

E

8

E

Слайд 129

Кратчайший маршрут длины кратчайших маршрутов из A в другие вершины A

Кратчайший маршрут

длины кратчайших маршрутов из A в другие вершины

A → C

→ E → F
Слайд 130

Алгоритм Дейкстры const N = 6; var W: array[1..N,1..N] of integer;

Алгоритм Дейкстры

const N = 6;
var W: array[1..N,1..N] of integer;
active: array

[1..N] of boolean;
R, P: array [1..N] of integer;
i, j, min, kMin: integer;

Данные:

Начальные значения (выбор начальной вершины):

for i:=1 to N do begin
active[i]:= True; { вершины не выбраны }
R[i]:= W[1,i]; { только маршруты из A }
P[i]:= 1 { вершина A }
end;
active[1]:= False; { вершина A выбрана }
P[1]:= 0; { это начало маршрута }

Слайд 131

Алгоритм Дейкстры for i:= 1 to N-1 do begin min:= MaxInt;

Алгоритм Дейкстры

for i:= 1 to N-1 do begin
min:= MaxInt;

for j:= 1 to N do
if active[j] and (R[j] < min) then begin
min:= R[kMin];
kMin:= j
end;
active[kMin]:= False;
for j:= 1 to N do
if R[kMin] + W[kMin,j] < R[j] then begin
R[j]:= R[kMin] + W[kMin,j];
P[j]:= kMin
end
end;

Основной цикл:

выбор следующей вершины, ближайшей к A

проверка маршрутов через вершину kMin

Слайд 132

Алгоритм Дейкстры i:= N; { конечная вершина } while i 0

Алгоритм Дейкстры

i:= N; { конечная вершина }
while i < > 0

do begin
write(i:5);
i:= P[i] { к следующей вершине }
end;

Вывод результата (маршрут 1 → N):

для начальной вершины P[i]=0

Слайд 133

Алгоритм Флойда for k:= 1 to N do for i:= 1

Алгоритм Флойда

for k:= 1 to N do
for i:= 1 to

N do
for j:= 1 to N do
if W[i,k]+ W[k,j]< W[i,j] then
W[i,j]:= W[i,k]+ W[k,j];

Все кратчайшие пути (из любой вершины в любую):

Слайд 134

Алгоритм Флойда + маршруты for i:=1 to N do begin for

Алгоритм Флойда + маршруты

for i:=1 to N do begin
for j:=1

to N do
P[i,j]:= i;
P[i,i]:= 0
end;

Дополнительная матрица:

for k:= 1 to N do
for i:= 1 to N do
for j:= 1 to N do
if W[i,k]+ W[k,j]< W[i,j] then begin
W[i,j]:= W[i,k]+ W[k,j];
P[i][j]:= P[k][j]
end;

Кратчайшие длины путей и маршруты:

Слайд 135

Задача коммивояжера Коммивояжер (бродячий торговец) должен выйти из города 1 и,

Задача коммивояжера

Коммивояжер (бродячий торговец) должен выйти из города 1 и, посетив

по разу в неизвестном порядке города 2,3,...N, вернуться обратно в город 1. В каком порядке надо обходить города, чтобы путь коммивояжера был кратчайшим?

Точные методы:
простой перебор;
метод ветвей и границ;
метод Литтла;

Приближенные методы:
метод случайных перестановок (Matlab)
генетические алгоритмы
метод муравьиных колоний

большое время счета для больших N

O(N!)

не гарантируется оптимальное решение

Слайд 136

Некоторые задачи Задача на минимум суммы. Имеется N населенных пунктов, в

Некоторые задачи

Задача на минимум суммы. Имеется N населенных пунктов, в каждом

из которых живет pi школьников (i=1,...,N). Надо разместить школу в одном из них так, чтобы общее расстояние, проходимое всеми учениками по дороге в школу, было минимальным.
Задача о наибольшем потоке. Есть система труб, которые имеют соединения в N узлах. Один узел S является источником, еще один – стоком T. Известны пропускные способности каждой трубы. Надо найти наибольший поток от источника к стоку.
Задача о наибольшем паросочетании. Есть M мужчин и N женщин. Каждый мужчина указывает несколько (от 0 до N) женщин, на которых он согласен жениться. Каждая женщина указывает несколько мужчин (от 0 до M), за которых она согласна выйти замуж. Требуется заключить наибольшее количество моногамных браков.
Слайд 137

Алгоритмизация и программирование § 44. Динамическое программирование

Алгоритмизация и программирование

§ 44. Динамическое программирование

Слайд 138

Что такое динамическое программирование? Числа Фибоначчи: ; . F1 = F2

Что такое динамическое программирование?

Числа Фибоначчи:

;

.

F1 = F2 = 1
Fn =

Fn-1 + Fn-2, при n > 2

function Fib(N: integer):
integer;
begin
if N < 3 then
Fib:= 1
else Fib:= Fib(N-1) + Fib(N-2)
end;

повторное вычисление тех же значений

Слайд 139

Динамическое программирование Объявление массива: const N = 10; var F: array[1..N]

Динамическое программирование

Объявление массива:

const N = 10;
var F: array[1..N] of integer;

Заполнение массива:

F[1]:=

1; F[2]:= 1;
for i:= 3 to N do
F[i]:= F[i-1] + F[i-2];

F1 = F2 = 1
Fn = Fn-1 + Fn-2, при n > 2

нужны только два последних!

Слайд 140

Динамическое программирование Динамическое программирование – это способ решения сложных задач путем

Динамическое программирование

Динамическое программирование – это способ решения сложных задач путем сведения

их к более простым задачам того же типа.

1

2

5

ABE: 5 + 20 = 25

AСE: 2 + 30 = 32

ADE: 1 + 40 = 41

дополнительный расход памяти

увеличение скорости

Слайд 141

Количество вариантов Задача. Найти количество KN цепочек, состоящих из N нулей

Количество вариантов

Задача. Найти количество KN цепочек, состоящих из N нулей и

единиц, в которых нет двух стоящих подряд единиц.

Решение «в лоб»:

0/1

битовые цепочки

построить все возможные цепочки
проверить каждую на «правильность»

2N

Сложность алгоритма O(2N)

Слайд 142

Количество вариантов Задача. Найти количество KN цепочек, состоящих из N нулей

Количество вариантов

Задача. Найти количество KN цепочек, состоящих из N нулей и

единиц, в которых нет двух стоящих подряд единиц.

Простые случаи:

K1=2

N = 1:

0 1

K2=3

N = 2:

00 01 10

Общий случай:

KN-1 «правильных» цепочек начинаются с нуля!

KN-2 «правильных» цепочек начинаются с единицы!

KN-2

KN-1

KN = KN-1 + KN-2

= FN+2

Слайд 143

Оптимальное решение Задача. В цистерне N литров молока. Есть бидоны объемом

Оптимальное решение

Задача. В цистерне N литров молока. Есть бидоны объемом 1,

5 и 6 литров. Нужно разлить молоко в бидоны так, чтобы все бидоны были заполнены и количество используемых бидонов было минимальным.

Перебор?

при больших N – очень долго!

«Жадный алгоритм»?

N = 10:

10 = 6 + 1 + 1 + 1 + 1

10 = 5 + 5

K = 5

K = 2

Слайд 144

Оптимальное решение Сначала выбрали бидон… KN – минимальное число бидонов для

Оптимальное решение

Сначала выбрали бидон…

KN – минимальное число бидонов для N литров

KN

= 1 + KN-1

1 л:

KN = 1 + KN-5

5 л:

KN = 1 + KN-6

6 л:

min

KN = 1 + min (KN-1 , KN-5 , KN-6)

при N ≥ 6

KN = 1 + min (KN-1 , KN-5)

при N = 5

KN = 1 + KN-1

при N < 5

Рекуррентная формула:

Слайд 145

Оптимальное решение (бидоны) 1 1 2 1 3 1 4 1

Оптимальное решение (бидоны)

1

1

2

1

3

1

4

1

1

5

1

6

2

1

3

1

4

1

2

5

KN = 1 + min (KN-1 , KN-5 ,

KN-6)

2 бидона

5 + 5

Слайд 146

Задача о куче Задача. Из камней весом pi (i=1, …, N)

Задача о куче

Задача. Из камней весом pi (i=1, …, N) набрать

кучу весом ровно W или, если это невозможно, максимально близкую к W (но меньшую, чем W).

камень
взят

камень
не взят

2N

Сложность алгоритма O(2N)

Решение «в лоб»:

Слайд 147

Задача о куче Задача. Из камней весом pi (i=1, …, N)

Задача о куче

Задача. Из камней весом pi (i=1, …, N) набрать

кучу весом ровно W или, если это невозможно, максимально близкую к W (но меньшую, чем W).

Идея: сохранять в массиве решения всех более простых задач этого типа (при меньшем количестве камней N и меньшем весе W).

Пример: W = 8, камни 2, 4, 5 и 7

w

pi

базовые случаи

T[i,w] – оптимальный вес, полученный для кучи весом w из i первых по счёту камней.

i

Слайд 148

Задача о куче Добавляем камень с весом 4: для w 0

Задача о куче

Добавляем камень с весом 4:

для w < 4 ничего

не меняется!

0

2

2

для w ≥ 4:

если его не брать:

T[2,w] = T[1,w]

если его взять:

T[2,w] = 4 + T[1,w-4]

max

4

4

6

6

6

Слайд 149

Задача о куче Добавляем камень с весом 5: для w 0

Задача о куче

Добавляем камень с весом 5:

для w < 5 ничего

не меняется!

0

2

2

4

5

6

7

7

Слайд 150

Задача о куче Добавляем камень с весом 7: для w 0

Задача о куче

Добавляем камень с весом 7:

для w < 7 ничего

не меняется!

0

2

2

4

5

6

7

7

Слайд 151

Задача о куче Добавляем камень с весом pi: для w Рекуррентная формула:

Задача о куче

Добавляем камень с весом pi:

для w < pi ничего

не меняется!

Рекуррентная формула:

Слайд 152

Задача о куче Оптимальный вес 7 5 + 2

Задача о куче

Оптимальный вес 7

5 + 2

Слайд 153

Задача о куче Заполнение таблицы: W+1 N псевдополиномиальный

Задача о куче

Заполнение таблицы:

W+1

N

псевдополиномиальный

Слайд 154

Количество программ Задача. У исполнителя Утроитель есть команды: 1. прибавь 1

Количество программ

Задача. У исполнителя Утроитель есть команды:
1. прибавь 1
2.

умножь на 3
Сколько есть разных программ, с помощью которых можно из числа 1 получить число 20?
Слайд 155

Количество программ Как получить число N: N если делится на 3!

Количество программ

Как получить число N:

N

если делится на 3!

последняя команда

Рекуррентная формула:

KN =

KN-1 если N не делится на 3
KN = KN-1 + KN/3 если N делится на 3
Слайд 156

Количество программ Заполнение таблицы: Рекуррентная формула: KN = KN-1 если N

Количество программ

Заполнение таблицы:

Рекуррентная формула:

KN = KN-1 если N не делится на

3
KN = KN-1 + KN/3 если N делится на 3

1

2

2

2

3

3

3

5

5

5

7

7

7

9

9

9

12

12

12

K2+K1

K5+K2

K8+K3

одна пустая!

Слайд 157

Количество программ Только точки изменения: 12 20 Программа: K[1]:= 1; for

Количество программ

Только точки изменения:

12

20

Программа:

K[1]:= 1;
for i:= 2 to N

do begin
K[i]:= K[i-1];
if i mod 3 = 0 then
K[i]:= K[i] + K[i div 3]
end;
Слайд 158

Размен монет Задача. Сколькими различными способами можно выдать сдачу размером W

Размен монет

Задача. Сколькими различными способами можно выдать сдачу размером W рублей,

если есть монеты достоинством pi (i=1, …, N)? В наборе есть монета достоинством 1 рубль (p1 = 1).

Перебор?

при больших N и W – очень долго!

Динамическое программирование:

запоминаем решения всех задач меньшей размерности: для меньших значений W и меньшего числа монет N.

Слайд 159

Размен монет Пример: W = 10, монеты 1, 2, 5 и

Размен монет

Пример: W = 10, монеты 1, 2, 5 и 10

w

pi

базовые

случаи

T[i,w] – количество вариантов для суммы w с использованием i первых по счёту монет.

i

Рекуррентная формула (добавили монету pi):

при w < pi:

при w ≥ pi:

T[i,w] = T[i-1,w]

T[i,w] = T[i-1,w] + T[i,w-pi]

все варианты размена остатка

T[i-1,w]

без этой монеты

T[i,w-pi]

Слайд 160

Размен монет Пример: W = 10, монеты 1, 2, 5 и

Размен монет

Пример: W = 10, монеты 1, 2, 5 и 10

Рекуррентная

формула (добавили монету pi):
Слайд 161

Конец фильма ПОЛЯКОВ Константин Юрьевич д.т.н., учитель информатики ГБОУ СОШ №

Конец фильма

ПОЛЯКОВ Константин Юрьевич
д.т.н., учитель информатики
ГБОУ СОШ № 163, г. Санкт-Петербург
kpolyakov@mail.ru

ЕРЕМИН Евгений Александрович
к.ф.-м.н., доцент кафедры мультимедийной дидактики и ИТО ПГГПУ, г. Пермь
eremin@pspu.ac.ru