- •Оценка эффективности алгоритмов
- •Целочисленная арифметика
- •Дано натуральное число. Выяснить является ли оно палиндромом, то есть читается справа налево и слева направо одинаково
- •Дано натуральное число. Выяснить соотношение между количествами двоек и пятерок в этом числе
- •Найти самую большую и самую маленькую цифры данного натурального числа
- •Выяснить образуют ли цифры натурального числа возрастающую последовательность
- •Формат выходного файла
- •Формат входного файла
- •Формат выходного файла
- •Формат входного файла
- •Формат входного файла
- •Формат выходного файла
- •Длинная арифметика
- •Выходные данные
- •Задачи Задача 52 Иностранные земли
- •Входные данные.
- •Выходные данные.
- •Формат входного файла
- •Формат выходного файла
- •Задачи Задача 56 Уравнение
- •Решение
- •Одномерные массивы
- •Базовые задачи на массивы
- •Задача 15 Сокращение одночленов
- •Входные данные:
- •Задача 16 Школьный субботник
- •Входные данные:
- •Входные данные:
- •Выходные данные:
- •Примеры
- •Задача 27 Решение систем линейных уравнений на Pascal
- •Двумерные массивы
- •Описание массива
- •Способы создания массива
- •Задачи:
- •Задача 5 Малыш играет в "Морской бой 2" Малыш играет в "Морской бой". Поле для игры представляет собой квадрат
- •Входные данные
- •Выходные данные
- •Задача 26 Шарик в лабиринте
- •Примечание
- •Задача 27 Блохи
- •В первой строке входного файла Input.Txt находится 5 чисел, разделенных пробелом: n, m, s, t, q.
- •Входные данные
- •Выходные данные
- •Примеры
- •Задача 34 Магический квадрат
- •Формат входного файла
- •Формат выходного файла
- •Входные данные
- •Выходные данные
- •Входные данные
- •Выходные данные
- •Рекурсия
- •Комбинаторика
- •2.5. Генерация комбинаторных объектов
- •Множество всех подмножеств
- •Перестановки
- •Размещения
- •Перестановки с повторениями
- •Сочетания с повторениями
- •Перебор
- •Символ o()
- •Отсечение по времени
- •Рассмотрим несколько олимпиадных задач.
- •Шарик в лабиринте
- •Задача 1. Шарик в лабиринте
- •Задача 3 Цепочка слов
- •Входные данные
- •Выходные данные
- •Примеры
- •Формат входного файла
- •Формат выходного файла
- •Примеры
- •Динамическое программирование
- •Задача 8 Гвоздики
- •Задача 13 Лесенки
- •Задача 18 Свинья-копилка
- •Входные данные
- •Выходные данные
- •Задача 13 Лесенки Лесенкой называется набор кубиков, в котором каждый более верхний слой содержит кубиков меньше, чем предыдущий.
- •Задача 18 Свинья-копилка
- •Формат входного файла:
- •Формат выходного файла:
- •Примеры
- •Решение
- •Входные данные:
- •Выходные данные:
- •Формат входа
- •Формат выхода
- •Задача 39 Лесенка-2
- •Входные данные
- •Выходные данные
- •Примеры
- •Системы счисления
- •Задача 11 Троичная сбалансированная система счисления
- •Алгоритм перевода
- •Процедуры и функции для работы с символами и строками
- •Определить количество слов в строке
- •Получите строковой массив из всех слов данной строки
- •Получите строковой массив из всех слов данной строки и
- •Получите строковой массив из всех слов данной строки и
- •Составьте программу, определяющую, является ли введенное слово изображением числа
- •Введите 2 целых числа. Преобразуйте числа в две строки, объедините их в одну строку и выведите результат на экран.
- •Вычислите длину самого короткого и самого длинного слов в строке
- •Подсчитайте количество букв в каждом слове данной строки
- •Дана строка. Определить количество слов этой строки, в которых есть ровно две буквы «е»
- •Составьте программу, удаляющую все лишние пробелы из введенной строки
- •Напишите программу, сортирующую символы введенной с клавиатуры строки в порядке возрастания их номеров в ascii-таблице. Например, если введено: 'cba', в результате надо получить ‘abc’.
- •В тексте, состоящем из маленьких латинских букв , подсчитайте количество гласных букв
- •Заданы фамилия, имя и отчество учащегося, разделенные пробелом. Напечатайте его фамилию и инициалы.
- •Сложное слово состоит из двух частей одинаковой длины и соединительной гласной. Найдите обе части этого слова.
- •Вычеркните из слова х те буквы, которые встречаются в слове z
- •Подсчитайте число различных букв в слове
- •Даны два слова. Составьте программу, определяющую можно или нет из букв слова а составить слово в.
- •Даны два слова. Являются ли они анаграммами
- •Является ли данная строка палиндромом?
- •Задача 4. Сокращение одночленов
- •Входные и выходные данные
- •Это чисто техническая задача на аккуратное программирование.
- •Задача 6 Текст
- •Входной файл Input.Txt в первой строке входного файла находится 5 чисел,разделенных пробелом: n, m, s, t, q.
- •Бинарные деревья. Алгоритм HeapSort
- •Поиск в глубину в графе
- •Алгоритм Флойда поиска кратчайших расстояний и кратчайших путей
- •Бинарные деревья. Алгоритм HeapSort
- •Графызадачи Двоичная куча
- •Примеры задач, которые решаются с помощью двоичной кучи
- •Поиск максимального потока методом Форда-Фалкерсона на Pascal
- •Графызадачи Поиск сильно связанных компонент на Pascal
- •Поиск точек раздела, мостов и двусвязных компонент
- •Идеи алгоритмов
- •Точки раздела
- •Двусвязные компоненты
- •Задача 21 Моя Столица
- •Вычислительная геометрия
- •3. Уравнение прямой 2
- •4. Уравнение прямой проходящей через точку м(х0у0)
- •Формат входного файла
Задача 13 Лесенки Лесенкой называется набор кубиков, в котором каждый более верхний слой содержит кубиков меньше, чем предыдущий.
Подсчитать число лесенок, которое можно построить из N кубиков.
Входные данные
Во входном файле записано число N (1N100).
Выходные данные
В выходной файл вывести искомое число лесенок.
Пример
Input.txt |
Output.txt |
3 |
2 |
Переформулируем нашу задачу на язык математики. В каждом следующем слое (считая сверху вниз) кубиков больше, чем в предыдущем, а в сумме их n. Значит, нам требуется представить n в виде суммы возрастающих натуральных слагаемых.
---
1 | |
---------
4 | | | | |
-----------
5 | | | | | |
-----------------
8 | | | | | | | | |
-----------------
n=1+4+5+8
Пусть в качестве первого слагаемого мы взяли L, тогда нам требуется n-L разбить на слагаемые. Но теперь добавляется дополнительное условие - слагаемые должны быть больше либо равны L+1. Значит, нам достаточно научиться считать число разбиений числа n на слагаемые не меньшие k (обозначим an,k). Есть два случая: слагаемое k либо входит в разбиение (таких способов an-k,k+1), либо нет (таких способов an,k+1). Так как никакое разбиение не подходит одновременно под оба эти случая, то an,k=an-k,k+1+an,k+1 Заметим, что для единицы существует единственное разбиение: 1 = 1. Значит a1,0 = a1,1 = 1, a1,f = 0, где f >= 2. an,k удобно вычислять в порядке невозрастания k. При равных k - в произвольном порядке. Данный алгоритм выполняет порядка N2 действий.
program lesenki;
const nmax=100;mmax=100;
Var
a:array[0..nmax,0..mmax] of integer;
i,j,n,t,k:integer;
Begin
assign(input,'input.txt');
reset(input);
assign(output,'output.txt');
rewrite(output);
read(n);
for j:=1 to n do заполняем первую строку нулями
a[1,j]:=0; первые два элемента 1
a[1,0]:=1;
a[1,1]:=1;
for j:=1 to n do один способ представить число j
слагаемыми
a[j,j]:=1; не меньшими j
a[2,1]:=1;a[2,2]:=1;a[2,0]:=1; заполняем вторую строчку для числа 2
for i:=3 to n do перебираем строки, начиная с третьей
begin
k:=i-1; начиная с этого столбца
while k>0 do двигаемся к первому
begin
a[i,k]:=a[i-k,k+1]+a[i,k+1]; и вычисляем элементы матрицы
dec(k);
end;
end;
write(a[n,1]); выводим результат
End.
динампрогрзадачи
Задача 14 Шаблон и слово
Будем рассматривать слова из больших латинских букв и шаблоны, состоящие из больших латинских букв и символов "?" и "*". Говорят, что слово подходит под шаблон, если в шаблоне можно заменить каждый символ "?" на большую латинскую букву, а каждый символ "*" - на
последовательность (возможно, пустую) больших латинских букв, так, чтобы получилось требуемое слово. Напишите программу, которая определит, подходит ли слово под шаблон.
Входные данные:
в первых двух строках записаны шаблон и слово:
в одной строки записан шаблон - последовательность больших латинских букв, "?" и "*", в другой - слово, состоящее только из больших латинских букв (строки короче 256 символов).
Выходные данные: вывести YES, если слово подходит или NO, если нет.
Пример:
Input.txt |
Output.txt |
ABBCDA A*CDA |
YES
|
AADAAVA A*DA*AA* |
NO
|
Для начала определим, какая из введенных строк является словом, а какая - шаблоном. Та строка, в которой есть символы '?' или '*' - шаблон. Если ни в одной из строк их нет, то в качестве шаблона возьмем произвольную. Будем определять, может ли часть слова (обозначим s1)с 1-го по k-й символ соответствовать части шаблона (обозначим s2)с 1-го по m-й символ (обозначим ak,m). Теперь есть 3 варианта:
В шаблоне на m-м месте стоит буква. Тогда она соответствует последней букве слова и ak,m=(s1[k]=s2[m]) and ak-1,m-1
В шаблоне на последнем месте стоит '?'. Тогда он соответствует последней букве слова и ak,m=ak-1,m-1
В шаблоне на последнем месте стоит '*'. Тогда возможны два варианта: либо этой звездочке соответсвует пустая последовательность букв слова, либо непустая. Во втором случае в части слова с 1-го по k-1-й символ этой звездочке тоже соответствует некоторая последовательность букв (возможно пустая). Таким образом ak,m=ak-1,m or ak,m-1.
Осталось рассмотреть несколько моментов. Так как '*' может соответствовать пустая последовательность букв, то непустому шаблону вполне может соответствовать пустое слово, значит матрица a должна индексироваться не от 1, а от 0. Если же один из индексов отрицательный - то это всегда FALSE. Заметим, что абсолютно аналогично можно решать задачу про соответсвие двух шаблонов. Просто добавятся еще несколько случаев.
program shablon_slovo;
const nmax=100;
var a:array[0..nmax,0..nmax] of boolean;
tmp,s1,s2:string;
i,j,k,m:integer;
begin
assign(input,'input.txt');
reset(input);
assign(output,'output.txt');
rewrite(output);
readln(s1);
readln(s2);
for i:=1 to length(s2) do выбираем строку, которая
будет шаблоном
if (s2[i]='*') or (s2[i]='?')
then
begin tmp:=s1; s1:=s2; s2:=tmp; break; end; меняем строки местами
k:=length(s1);
m:=length(s2);
a[0,0]:=true;
for i:=1 to k do заполняем матрицу
for j:=1 to m do
begin
if s1[i] in ['A'..'Z'] если символ буква
then a[i,j]:=(s1[i]=s2[j]) and a[i-1,j-1];
if s1[i]='?' then a[i,j]:=a[i-1,j-1]; если символ знак вопроса
if s1[i]='*' then a[i,j]:=a[i-1,j] or a[i,j-1]; если символ звездочка
end;
if a[k,m] then write('YES') else write('NO'); выводим результат
close(input); close(output);
end.
динампрогрзадачи
Задача 15 Рюкзак 1_1
Найдите максимальный вес золота, который можно унести с рюкзаком вместительностью W килограмм, если есть N слитков массой a1,a2, … an килограмм. Все веса — натуральные числа, не превосходящие 100000.
Входные данные:
В первой строке входного файла записаны два числа —N и W (1 N 300,1 W 10000). Далее следует N чисел — веса слитков.
Выходные данные:
Выведите искомый максимальный вес.
Пример:
Input.txt |
Output.txt |
2 10 5 6 |
6 |
В этой задаче можно считать, что все слитки в одном экземпляре и в решении можно обойтись одномерным массивом.
Program rjkzak;
const nmax = 10000;
var i,j,w,n, k, s,ans : longint;
b : array [0..nmax] of boolean;
begin
assign(input,’input.txt’);
reset(input);
assign(output,’output.txt’);
rewrite(output);
read(n,w);
fillchar(b,sizeof(b),false);
b[0]:= true;
for i:= 1 to n do перебираем слитки
begin
read(x); считываем вес очередного слитка
for j:= w-x downto 0 do выясняем можно ли взять этот слиток, перебирая
все веса от s-x до 0
if b[j] если к набранному весу j можно добавить
then b[j+x]:= true; последний слиток, то берем его
end;
for i:= w downto 0 do выводим максимальный вес взятых слитков
if b[i] then
begin
ans:= i;
break;
end;
write(ans);
close(input); close(output);
end.
динампрогрзадачи
Задача 16 Рюкзак 1_2
Имеется набор N предметов различного веса и разной стоимости. Максимальный вес рюкзака W. Набрать в рюкзак предметы максимальной стоимости, совокупный вес которых не превышает вес рюкзака. Все предметы в одном экземпляре.
Входные данные:
В первой строке входного файла записаны два числа — N и W (1 N 300;1 W 10000). Во второй строке N чисел — веса предметов и в третьей строке N чисел – стоимости предметов. Все числа не превышают 30000.
Выходные данные:
Выведите в первой строке искомую максимальную стоимость, а во второй номера взятых предметов.
Пример:
Input.txt |
Output.txt |
4 6 2 3 1 4 50 90 30 140 |
190 1 4 |
Пусть элемент Ci массива C соответствует стоимости i-го предмета, а элемент Vi массива V - весу i-го предмета. Будем считать, что предметы пронумерованы в порядке их следования в таблицах. Пусть A обозначает функцию, значение которой соответствует решению нашей задачи. Аргументами функции является количество предметов (по этому аргументу можно определить их стоимости и веса соответствующих предметов), а также максимальный суммарный вес, который можно взять. Определим подзадачи A(i, j), где i обозначает количество начальных предметов, из которых можно осуществлять выбор, а j определяет максимально возможный суммарный вес взятых предметов. Отметим, что определенный таким образом первый параметр i определяет как количество предметов для подзадачи,
так и значения их стоимостей и весов, определяемых из массивов C и V. Определим сначала начальные значения функции А. При нулевых значениях одного из аргументов значение функции равно нулю:
A(0,0)=0
A(0,j)=0 при j>=1,
A(i,0)=0 при i>=1.
Определим возможные значения функции A(i, j) при ненулевых значениях аргументов.
Решение подзадачи, соответствующей функции A(i, j) может быть сведено к двум возможностям: уносится ли при наилучшем решении предмет с номером i или нет.
Если предмет не берется, то решение задачи с i предметами сводится к решению подзадачи с i-1 предметами, т. е. A(i,j)=A(i-1,j).
Если предмет c номером i берется, то это уменьшает максимально возможную суммарную массу для i-1 первых предметов на величину V[i], одновременно при этом увеличивая значение решения для оставшихся предметов A(i-1,j-v[i]) на величину C[i], т. е. A(i,j)=A(i-1,j-v[i])+C[i].
При этом необходимо учитывать, что вторая ситуация возможна только тогда, когда вес i-го предмета не больше значения j. Для получения наилучшего решения необходимо выбрать лучшую из этих двух возможностей. Поэтому рекуррентное соотношение при i>=1 и j>=1 имеет вид
A(i,j)=A(i-1,j) при j<v[i] и
A(i,j)=max(A(i-1,j),A(i-1,j-v[i]) + C[i]) при j>=v[i].
Пусть заданы следующие значения стоимости и весов для 5 предметов:
C[1] = 5 V[1] = 4
C[2] = 7 V[2] = 5
C[3] = 4 V[3] = 3
C[4] = 9 V[4] = 7
C[5] = 8 V[5] = 6
W=16
Таблица значений функции T, которую мы также назовем T, выглядит следующим образом:
i\j 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5 5 5
2 0 0 0 0 5 7 7 7 7 12 12 12 12 12 12 12 12
3 0 0 0 4 5 7 7 9 11 12 12 12 16 16 16 16 16
4 0 0 0 4 5 7 7 9 11 12 13 14 16 16 18 20 21
5 0 0 0 4 5 7 8 9 11 12 13 15 16 17 19 20 21
Следовательно, решение задачи A(5,16)=21. Однако это не значит автоматически, что суммарный вес взятых предметов равен 16,он может быть и меньше. Действительно, A(1,16)=5, а соответствующая этой подзадаче суммарный вес предметов равен 4.
Для выяснения номеров элементов, вошедших в множество взятых предметов, достаточно, начав с элемента с индексами [i,j] (которые вначале равны N и W соответственно),сравнить его со значением a[i-1,j]. Если значения равны, то i элемент не входит в множество, а процесс повторяется для элемента с индексами [i-1,j]. В случае неравенства элементов элемент i входит в множество, а процесс повторяется для элемента с индексами [i-1,j-V[i]]. Процесс выполняется для всех i от N до 1.
Const MaxN=50;
MaxW=600;
Var a:Array [0..MaxN,0..MaxW] Of Word;
v,c:Array [1..Maxn] of integer;
i,j,N,W:Integer;
function max(x,y:integer):integer;
begin
if x>y then max:=x
else max:=y;
end;
Procedure Init;
Begin
Assign(input,'input.txt');
Reset(input);
Assign(output,'output.txt');
Rewrite(output);
read(n);read(w);
for i:=1 to n do
read(v[i]);
for i:=1 to n do
read(c[i]);
End;
Procedure Solve;
Var t:Integer;
Begin
FillChar(a,SizeOf(a),0);
For i:=1 to n do цикл по видам предметов
for j:=1 to w do цикл по набранному весу
if j >= v[i] если набираемый вес j больше веса i-го
предмета, т.е.
then предмет можно взять
a[i, j]:= max(a[i-1,j],a[i-1,j-v[i]]+C[i]) выбираем лучший результат
else
a[i, j]:=a[i-1,j] предмет i не берем
End;
Procedure OutWay(i,j:integer);
Begin
If i=0 если предметы кончились,то
Then Exit выходим
Else Begin иначе
if a[i,j]=a[i-1,j] если i-ый предмет не взяли
then outway(i-1,j) переходим на строку выше и вызываем
outway
else
begin
outway(i-1,j-v[i]); если взяли, то переходим на строку
выше в клетку с весом j-v[i]
write(i,' '); выводим i
end;
End;
End;
Begin
Init;
Solve;
Writeln(a[n,w]); выводим максимальную стоимость взятых
предметов
OutWay(n,w); выводим номера взятых предметов
End.
динампрогрзадачи
Задача 17 Рюкзак 2
Имеется набор N предметов различного веса и разной стоимости. Максимальный вес рюкзака W. Набрать в рюкзак предметы максимальной стоимости, совокупный вес которых не превышает вес рюкзака. Предметов каждого типа бесконечно много.
Входные данные:
В первой строке входного файла записаны два числа — N и W(1 N 300;1 W 10000). Во второй строке N чисел — веса предметов и в третьей строке N чисел – стоимости предметов. Все числа не превышают 30000.
Выходные данные:
Выведите в первой строке искомую максимальную стоимость, а в последующих строках номер взятого предмета и количество.
Пример:
-
Input.txt
Output.txt
6 45
7 10 15 20 27 34
4 7 11 12 16 27
34
2 1
6 1
4 6
2 3 1 4
50 90 30 140
200
3 2
4 1
program rukzak2;
Const MaxN=100;
MaxW=100;
Var a,b:Array [0..MaxN,0..MaxW] Of Word; в массиве b храним количество
взятых предметов каждого вида
c,v:Array [1..MaxW] Of Longint;
i,j,n,w:Integer;
Procedure Init;
Begin
assign(input,'input.txt');
reset(input);
assign(output,'output.txt');
rewrite(output);
read(n,w); считываем количество видов предметов и
вместимость рюкзака
for i:=1 to n do read(v[i]); считываем веса
for i:=1 to n do read(c[i]); считываем стоимости
End;
Procedure Solve;
Var k,i,j:Integer;
Begin
fillchar(b,sizeof(b),0);
For i:=1 To N Do цикл по видам предметов
For j:=0 To W Do цикл по набранному весу
For k:=0 To j Div v[i] Do цикл по количеству предметов каждого вида
If j-k*v[i]<0 если К предметов вида i взять нельзя
Then
a[i,j]:=a[i-1,j] сохраняем предыдущий результат
else
if k*c[i]+a[i-1,j-k*v[i]]>a[i-1,j] сравниваем новый результат со старым
then
begin
a[i,j]:=k*c[i]+a[i-1,j-k*v[i]]; сохраняем лучший результат и
b[i,j]:=k; количество взятых предметов i-го вида
end
else
a[i,j]:=a[i-1,j]; сохраняем лучший результат
end;
Procedure OutWay(i,j:integer); выводим наибольшую стоимость и в кажой
из n следующих N строк номер предмета и его количество
Begin
If i=0
Then Exit
Else Begin
if a[i,j]=a[i-1,j]
then outway1(i-1,j)
else
begin
outway1(i-1,j-b[i,j]*v[i]);
writeln(i,' ',b[i,j]); выводим результат на подъеме из рекурсии
end;
End;
End;
Begin
Init;
Solve;
writeln(a[n,w]);
outway(n,w);
End.
динампрогрзадачи
