Приклад виконання роботи
Приклад 1. Завдання про розрізування прямокутника на квадрати.
Дано прямокутник, сторони якого виражені натуральними числами. Розріжте його на мінімальне число квадратів з натуральними сторонами. Знайдіть число квадратів, що вийшли.
Розробимо рекурсивну тріаду.
Параметризація: m, n - натуральні числа, що відповідають розмірам прямокутника.
База рекурсії: для m=n число квадратів, що вийшли, дорівнює 1, тому що даний прямокутник уже є квадратом.
Декомпозиція: якщо m≠n, те можливі два випадки m < n або m > n. Відрізаємо від прямокутника найбільший по площі квадрат з натуральними сторонами. Довжина сторони такого квадрата дорівнює найменшої зі сторін прямокутника. Після того, як квадрат буде відрізаний, розміри прямокутника стануть наступні: більша сторона зменшиться на довжину сторони квадрата, а менша не зміниться. Число шуканих квадратів буде обчислюватися як число квадратів, на які буде розрізаний отриманий прямокутник, плюс один (відрізаний квадрат). До прямокутника, що вийшов, застосуємо аналогічні міркування: перевіримо на відповідність базі або перейдемо до декомпозиції (рис. 2).
Рисунок 2. Приклад розрізування прямокутника 135 на квадрати
#include "stdafx.h"
#include <iostream>
using namespace std;
int kv(int m,int n);
int _tmain(int argc, _TCHAR* argv[]) {
int a,b,k;
printf("Введіть сторони прямокутника ->");
scanf("%d%d",&a,&b);
k = kv(a,b);
printf("Прямокутник зі сторонами %d и %d можна розрізати
на %d квадратів",a,b,k);
system("pause");
return 0;
}
int kv(int m,int n){ //m,n – сторони прямокутника
if(m==n) return 1; //база рекурсії
if(m>n) return 1+kv(m-n,n); //декомпозиція для m>n
return 1+kv(m,n-m); //декомпозиція для m<n
}
Характеристиками розглянутого методу оцінки алгоритму будуть наступні величини (рис. 34.3).
D = (13, 5) |
D = (m, n), m n, гірший випадок |
R(D)=6 |
R(D)=m |
RV(D)=4 |
RV(D)=m-2 |
RL(D)=1 |
RL(D)=1 |
HR(D)=6 |
HR(D)=m |
Рисунок 3. Приклад повного дерева рекурсії для розрізування прямокутника 135 на квадрати
Приклад 2. Завдання про розбивку цілого на частині.
Знайдіть кількість розбивок натурального числа на суму натуральних доданків.
Розбивка має на увазі подання натурального числа у вигляді суми натуральних доданків, при цьому суми повинні відрізнятися набором чисел, а не їхньою послідовністю. У розбивку також може входити одне число.
Наприклад, розбивка числа 6 буде представлено 11 комбінаціями:
6
5+1
4+2, 4+1+1
3+3, 3+2+1, 3+1+1+1
2+2+2, 2+2+1+1, 2+1+1+1+1
1+1+1+1+1+1
Розглянемо рішення в загальному виді. Нехай залежність R(n,k) обчислює кількість розбивок числа n на суму що складають, не переважаючих k. Опишемо властивості R(n,k).
Якщо в сумі всі доданки не перевершують 1, то таке подання єдине, тобто R(n,k)=1.
Якщо розглянуте число дорівнює 1, то при будь-якім натуральному значенні другого параметра розбивка також єдина: R(n,k)=1.
Якщо другий параметр перевершує значення першого , то має місце рівність R(n,k)=R(n,n), тому що для подання натурального числа в суму не можуть входити числа, що перевершують його.
Якщо в суму входить доданок, рівне першому параметру, то таке подання також єдине (містить тільки цей доданок), тому має місце рівність:R(n,n)=R(n,n-1)+1.
Якщо в торбу входити доданок, рівне першому параметру, те таке подання також єдине (містить тільки цей доданок), тому має місце рівність: (n>k). Розіб'ємо всі подання числа n на непересічні розкладання: в одні обов'язково буде входити доданок k, а інші суми не містять k. Перша група сум, що містить k, еквівалентна залежності R(n-k,k), що треба після вирахування числа k з кожної суми. Друга група сум містить розбивку числа n на доданки, кожне з яких не перевершує k-1, тобто число таких подань дорівнює R(n,k-1). Тому що обидві групи сум не перетинаються, то R(n,k)=R(n-k,k)+R(n,k-1).
Розробимо рекурсивну тріаду.
Параметризація: Розглянемо розбивку натурального числа n на суму таких що складають, які не перевершують натурального числа k.
База рекурсії: виходячи із властивостей розглянутої залежності, виділяються два базових випадки:
при n=1 R(n,k)=1,
при k=1 R(n,k)=1.
База рекурсії: виходячи із властивостей розглянутої залежності, виділяються два базових випадки:
при n=k R(n,k)=R(n,n-1)+1,
при n<k R(n,k)=R(n,n),
при n>k R(n,k)=R(n-k,k)+R(n,k-1).
#include "stdafx.h"
#include <iostream>
using namespace std;
unsigned long int Razbienie(unsigned long int n,
unsigned long int k);
int _tmain(int argc, _TCHAR* argv[]){
unsigned long int number, max,num;
printf ("\nВведіть натуральне число: ");
scanf ("%d", &number);
printf ("Введіть максимальний натуральний додаток в
сумі: ");
scanf ("%d", &max);
num=Razbienie(number,max);
printf ("Число %d можна представити у вигляді суми з
максимальним доданком %d.", number, max);
printf ("\nКількість розбивок дорівнює %d",num);
system("pause");
return 0;
}
unsigned long int Razbienie(unsigned long int n,
unsigned long int k){
if(n==1 || k==1) return 1;
if(n<=k) return Razbienie(n,n-1)+1;
return Razbienie(n,k-1)+Razbienie(n-k,k);
}