Azalan ədəd#1560

Azalan ədəd (Həll təhlili)

ədədini -ə çevirmək üçün tələb olunan minimum əməliyyat sayını ilə işarə edək. Məsələn,

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.

ə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:

f(n) = min(f(n - 1), f(n / 2), f(n / 3)) + 1, \\ f(1) = 0

Ə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:

f(8) = min(f(7), f(4)) + 1

Eyni şəkildə, n = 7 üçün əldə edirik:

f(7) = min(f(6)) + 1 = f(6) + 1

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,

d[10] = min(d[9], d[5]) + 1 = min(2, 3) + 1 = 3

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] * 1000001

massivinin 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] += 1

Hər bir giriş qiyməti üçün cavabını çap edin.

while True:
  try:
    n = int(input())
    print(d[n])
  except EOFError:
    break