Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие часть 1.doc
Скачиваний:
58
Добавлен:
24.09.2019
Размер:
6.98 Mб
Скачать
    1. Первые примеры

В качестве первых примеров подобраны небольшие задачи-этюды, решение которых не требует никаких специальных знаний, но позволяет освоить или закрепить некоторые полезные приемы программирования, которые могут найти применение и при решении серьезных задач. Они сгруппированы по темам.

1.5.1. Введение в «длинную» арифметику

Иногда возникает необходимость выполнять вычисления над очень большими числами, которые не входят ни в один из стандартных числовых типов (вспомним, что тип — это множество допустимых значений и набор допустимых операций). В таком случае приходится придумывать какой-либо способ хранения таких больших чисел. Разумеется, весь набор арифметических операций в этом случае приходится реализовывать самостоятельно, так и возник термин «длинная» арифметика.

Наиболее простой способ хранения большого целого числа, который чаще всего и применяется, — использование целочисленного одномерного массива, каждый элемент которого хранит одну десятичную цифру числа. В этом случае реализация основных арифметических операций сводится к задаче обработки массивов и требует только хорошей техники программирования и аккуратности.

Для примера возьмем задачу поинтереснее, она предлагалась на одной из городских олимпиад для школьников.

Получить наименьшее натуральное число, обладающее следующими свойствами:

  1. Оканчивается на 5.

  2. При умножении его на 5 получается то же самое число, что и при переносе цифры 5 с последнего места на первое.

#include <iostream.h>

void main()

{

int a[100], k=1, d=0; a[0]=5;

do

{

a[k]=a[k-1]*5+d;

d=a[k]/10; a[k]=a[k]%10;

k++;

}

while ((d!=0)||(a[k-1]!=1));

cout<<"Here is a round number: ";

for (int i=k-1; i>=0; i--) cout<<a[i];

cout<<endl; cin.get();

}

1.5.2. Рекурсия

Пример 1. Последовательность чисел Фибоначчи определяется так:a(0)= 1, a(1) = 1, a(k) = a(k-1) + a(k-2) при k >= 2. Первые члены этой последовательности: 1 1 2 3 5 8 13 21 и т. д. Дано n, вычислить a(n).

Задача имеет очевидное нерекурсивное решение, имеющее сложность C*n. При больших n вычисления могут занять много времени, поэтому приведем быстрый рекурсивный алгоритм решения этой задачи. Пара соседних чисел Фибоначчи получается из предыдущей умножением на матрицу

|1 1|

|1 0|

(проверьте сами), так что задача сводится к возведению матрицы в степень n. Это можно сделать за C*log n действий тем же способом, что и для чисел (см. разд. 1.4.3).

#include <iostream.h>

typedef int Matr[2][2];

void mult(Matr t1, Matr t2, Matr p)

{ p[0][0] = t1[0][0]*t2[0][0] + t1[0][1]*t2[1][0];

p[0][1] = t1[0][0]*t2[1][0] + t1[0][1]*t2[1][1];

p[1][0] = t1[1][0]*t2[0][0] + t1[1][1]*t2[1][0];

p[1][1] = t1[1][0]*t2[1][0] + t1[1][1]*t2[1][1];

}

void power(Matr t, int n)

{ Matr tmp,tmp2;

if (n==0)

{ t[0][0] = 1; t[1][1] = 1; t[1][0] = 0; t[0][1] = 0;

return;

}

if (n%2==0)

{ power(t,n/2); mult(t,t,tmp); memcpy(t,tmp,4*sizeof(int));

}

else

{ memcpy(tmp,t,4*sizeof(int)); power(t,n-1); mult(tmp,t,tmp2);

memcpy(t,tmp2,4*sizeof(int));

}

}

int main(void)

{ Matr t = {1,1,1,0};

power(t,10); cout << t[0][0] << endl;

return 0;

}

Многие задачи, требующие перебора различных вариантов, имеют компактное рекурсивное решение. Приведем пример одной из таких задач.

Пример 2. Перечислить все представления положительного целого числа n в виде суммы последовательности невозрастающих целых положительных слагаемых. Например, для числа 3 таких представлений будет всего два:

2+1 и 1+1+1.

#include <iostream.h>

int a[1000];

void summa(int n, int max, int k)

{ if (n<max) max=n;

for (int i=max; i>0; i--)

{ a[k]=i;

if (i==n)

{ for (int i=0; i<k; i++) cout<<a[i]<<"+";

cout<<a[k]<<endl;

}

else summa(n-i,i,k+1);

}

}

void main()

{ int n;

cout<<"Введите число N: "; cin>>n;

summa(n,n,0);

}