ədədini -ə çevirmək üçün tələb olunan minimum əməliyyat sayını ilə işarə edək. Məsələn,
f(1) = 0, çünki artıq ədədinə sahibik;
f(2) = 1, 2 → 1 əməliyyatını yerinə yetiririk;
f(5) = 3, 5 → 4 → 2 → 1 əməliyyatlarını yerinə yetiririk;
f(10) = 3, 10 → 9 → 3 → 1 əməliyyatlarını yerinə yetiririk;
n = 10 halında, acgöz yanaşmadan istifadə edib -yə bölmək əvəzinə əvvəlcə çıxmaq daha sərfəlidir.
funksiyasının hesablanması prosesinə baxaq.
Əgər ədədini -ə bölsək (fərz edək ki, ədədi -ə bölünür), onda
Əgər ədədini -yə bölsək (fərz edək ki, ədədi -yə bölünür), onda
Əgər ədədindən çıxsaq, onda
ədədindən , və ya n - 1 ədədlərindən birini əldə edə bilərik. Bu ədədlərin hər birini -ə endirmək üçün tələb olunan əməliyyat sayı müvafiq olaraq , və f(i - 1)-ə bərabərdir. Bizi minimum əməliyyat sayı maraqlandırdığından, aşağıdakı əlaqəyə sahibik:
Əgər ədədi -yə (və ya -ə) bölünmürsə, onda funksiyasında müvafiq element ( və ya ) olmur. Məsələn, n = 8 üçün:
Eyni şəkildə, n = 7 üçün əldə edirik:
funksiyasının qiymətləri d[MAX] massivinin xanalarında saxlanılacaq, burada MAX = 10^6 + 1. massivinin xanalarını -dən 10^6-a qədər verilmiş rekurrent asılılığa uyğun doldurun. Məsələn, aşağıdakı cədvəldə 1 \le i \le 11 üçün qiymətləri göstərilib:
Məsələn,
Başqa sözlə, -u -yə bölmək əvəzinə ondan çıxmaq daha səmərəlidir.
Məşq
Aşağıdakı qiymətləri üçün qiymətlərini tapın:
Alqoritmin tətbiqi
massivini elan edin, burada -ci xana ədədini -ə çevirmək üçün tələb olunan minimum əməliyyat sayını saxlayır.
#define MAX 1000001
int d[MAX];massivinin xanalarını verilmiş düsturlara uyğun doldurun.
d[1] = 0;
for (i = 2; i < MAX; i++)
{
// d[i] = min(d[i/3],d[i/2],d[i-1]) + 1
d[i] = d[i - 1];
if (i % 2 == 0) d[i] = min(d[i], d[i / 2]);
if (i % 3 == 0) d[i] = min(d[i], d[i / 3]);
d[i]++;
}Hər bir giriş qiyməti üçün cavabını çap edin.
while(scanf("%d",&n) == 1)
printf("%d\n",d[n]);Alqoritmin tətbiqi — rekursiya
#include <stdio.h>
#include <string.h>
#define INF 2000000000
int i, res, n;
int dp[1000001];
int min(int a, int b, int c)
{
int res = a;
if (b < res) res = b;
if (c < res) res = c;
return res;
}
int f(int n)
{
if (n == 1) return 0;
if (dp[n] != -1) return dp[n];
int a = f(n - 1);
int b = (n % 2 == 0) ? f(n / 2) : INF;
int c = (n % 3 == 0) ? f(n / 3) : INF;
return dp[n] = min(a,b,c) + 1;
}
int main(void)
{
memset(dp, -1, sizeof(dp));
while (scanf("%d", &n) == 1)
{
res = f(n);
printf("%d\n", res);
}
return 0;
}Java tətbiqi
import java.util.*;
public class Main
{
public static int MAX = 1000001;
static int d[] = new int[MAX];
public static void main(String[] args)
{
Scanner con = new Scanner(System.in);
d[1] = 0;
for(int i = 2; i < MAX; i++)
{
d[i] = d[i-1] + 1;
if (i % 2 == 0) d[i] = Math.min(d[i], d[i/2] + 1);
if (i % 3 == 0) d[i] = Math.min(d[i], d[i/3] + 1);
}
while(con.hasNext())
{
int n = con.nextInt();
System.out.println(d[n]);
}
}
}Python tətbiqi
siyahısını yaradın, burada -ci xana ədədini -ə çevirmək üçün tələb olunan minimum əməliyyat sayını saxlayır.
d = [0] * 1000001massivinin xanalarını verilmiş düsturlara uyğun doldurun.
d[1] = 0
for i in range(2, 1000001):
d[i] = d[i - 1]
if i % 2 == 0 and d[i // 2] < d[i]:
d[i] = d[i // 2]
if i % 3 == 0 and d[i // 3] < d[i]:
d[i] = d[i // 3]
d[i] += 1Hər bir giriş qiyməti üçün cavabını çap edin.
while True:
try:
n = int(input())
print(d[n])
except EOFError:
break