본문 바로가기
코딩테스트/이코테

[CH3 그리디] 1이 될 때까지

by 의정부핵꿀밤 2021. 12. 4.
728x90

1이 될 때까지

어떠한 수 N이 1이 될 때까지 다음의 두 과정 중 하나를 반복적으로 선택하여 수행하려고 한다

단, 두 번째 연산은 N이 K로 나누어 떨어질 때만 선택할 수 있다

 

1. N에서 1을 뺀다

2. N을 K로 나눈다

 

예를 들어 N이 17, K가 4라고 하자.

이 때 1번의 과정을 한 번 수행하면 N은 16이 된다  => 1

이 후 2번의 과정을 두 번 수행하면 N은 1이 된다  => 2

결과적으로 이 경우 전체 과정을 실행한 횟수는 3이 된다. 이는 N을 1로 만드는 최소 횟수이다

 

N과 K가 주어질 때 N이 1이 될 때까지 1번 혹은 2번의 과정을 수행해야 하는 최소 횟수를 구하는 프로그램을 작성해라

 

[입력 조건]

  • 첫째 줄에 N(2<=N<=100,000)과 K(2<=K<=100,00)가 공백으로 구분되며 각각 자연수로 주어진다.
  • 이 때 입력으로 주어지는 N은 항상 K보다 크거나 같다

 

[출력 조건]

  • 첫째 줄에 N이 1이 될 때까지 1번 혹은 2번의 과정을 수행해야 하는 횟수의 최솟값을 출력한다

 

입력 예시)

25 5

 

출력 예시)

2

 


[풀이]

이 문제도 아이디어만 떠올리면 어렵지 않게 해결이 가능하다!

주어진 N에 대해서 '최대한 많이 나누기'를 수행하면 된다 

왜냐면 2이상의 수가 주어지면, 그 수로 나누는게 1을 빼는 것보다 훨씬 숫자를 많이 줄일 수 있기 때문이다!

따라서 다음의 과정을 더이상 반복할 수 없을 때까지 반복하면 된다

  1. N이 K의 배수가 될 때까지 1씩 빼기
  2. N을 K로 나누기

Q. 근데 위의 풀이가 최적의 해를 보장한다는 것은 어떻게 알지?

A. 사실 당연한거다~!

 

문제 조건을 보면 K는 항상 2보다 크고, 2보다 큰 수로 숫자를 나누는게 1씩 빼는 것보다 훨씬 빠르게 숫자를 줄일 수 있고, 이는 N이 클수록 더 빨리 줄어든다.

즉, 이게 맞다 이말이다~~

 

이걸 코드로 구현할 때 반복문을 통해서 배수인지 확인하고 아니면 1을 뺴고, 뭐 이런식으로 구현을 해도 되긴 하지만 난 책에서 알려준 보다 효율적으로 구현하는 방식을 사용해서 구현해볼것이다. 그리고 이건 뭔가 C로 푸는게 더 빠를 것 같아서 C++로 풀어보려고 한다!

 


C++ 코드)

#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
    int n, k, target, result=0;
    cin >> n >> k;
    
    while(1)
    {
        target=(n/k)*k; //n이 될 수 있는 가장 큰 k의 배수
        result += (n-target); //n이 앞에서 구한 k의 배수가 되기 위해 빼준 횟수를 더해준다
        n=target;
        
        if(n<k) break; //n을 k로 나눌 수 없는 경우 반복문 탈출
        
        n/=k; //n을 k로 나누기
        result++; //한 번 나눴으니까 1 추가
    }
    
    result += (n-1); //n이 1이 되기 위해 빼줘야 하는 남은 횟수를 다 더해준다
    cout<<result;

    return 0;
}

먼저 반복문을 통해 나눌 수 있는 만큼 최대한으로 나눠준다

target을 이용해서 n이 k의 배수가 되기 위해 최소한으로 빼줘야 하는 1의 횟수를 구한다

예를 들어 n=25, k=3이면 target=(25/3)*3=24가 된다

그러면 result에는 25-24=1을 더해준다

25가 24가 되려면 1만 빼주면 되니까 맞게 계산되는 것이다

이런식으로 구현하면 반복문으로 이게 배수인지 아닌지 계속해서 확인하는 것보다 효율적으로 풀 수 있다!

 

그리고 n이 k보다 작으면 더이상 나눌 수 없으므로 반복문을 탈출하고, 그게 아니면 n을 k로 나눠주고 result에 1을 더해준다 (2번 과정을 한 번 실행했으니깐)

 

반복문을 탈출하면 n을 더이상 k로 나눌 수 없으니까 남은 방법은 1씩 빼주는 것 뿐이다

그래서 result에 n-1을 더해주는데 이는 n이 1이 되기 위해 빼줘야 하는 횟수이다

 

이건 단순한 결과 화면~


아 오늘은 좀 일찍 잠들었는데 또 새벽에 깨버려서 그냥 문제 하나 풀었당,,

잠 깬 김에 과제랑 시험공부하다가 마지막 UMC 서버 수업들어야징ㅠㅠ

그럼 빠잉!

728x90

댓글