Outdated/Algorithm Solution

[BOJ] 2343번 기타 레슨

해달 2020. 2. 22. 08:00

문제

강토는 자신의 기타 레슨 동영상을 블루레이로 만들어 판매하려고 한다. 블루레이에는 총 N개의 레슨이 들어가는데, 블루레이를 녹화할 때, 레슨의 순서가 바뀌면 안 된다. 순서가 뒤바뀌는 경우에는 레슨의 흐름이 끊겨, 학생들이 대혼란에 빠질 수 있기 때문이다. 즉, i번 레슨과 j번 레슨을 같은 블루레이에 녹화하려면 i와 j 사이의 모든 레슨도 같은 블루레이에 녹화해야 한다.


강토는 이 블루레이가 얼마나 팔릴지 아직 알 수 없기 때문에, 블루레이의 개수를 가급적 줄이려고 한다. 오랜 고민 끝에 강토는 M개의 블루레이에 모든 기타 레슨 동영상을 녹화하기로 했다. 이때, 블루레이의 크기(녹화 가능한 길이)를 최소로 하려고 한다. 단, M개의 블루레이는 모두 같은 크기이어야 한다.


강토의 각 레슨의 길이가 분 단위(자연수)로 주어진다. 이때, 가능한 블루레이의 크기 중 최소를 구하는 프로그램을 작성하시오.


입력

첫째 줄에 레슨의 수 N (1 ≤ N ≤ 100,000)과 M (1 ≤ M ≤ N)이 주어진다. 다음 줄에는 강토의 기타 레슨의 길이가 레슨 순서대로 분 단위로(자연수)로 주어진다. 각 레슨의 길이는 10,000분을 넘지 않는다.


출력

첫째 줄에 가능한 블루레이 크기중 최소를 출력한다.


코드

  • C++ 17


#include <iostream>

#include <algorithm>

using namespace std;

 

int N, M;

int Lessons[100001];

 

int GetCount(int sz)

{

    int count = 0;

 

    int sum = 0;

    for (int i = 0; i < N; ++i)

    {

        sum += Lessons[i];

        if (sum == sz || sum + Lessons[i + 1] > sz)

        {

            sum = 0;

            ++count;

        }

    }

    if (sum)

        ++count;

 

    return count;

}

 

int main()

{

    ios::sync_with_stdio(false);

    cin.tie(nullptr);

    cout.tie(nullptr);

 

    int sum = 0, mx = 0;

    cin >> N >> M;

    for (int i = 0; i < N; ++i)

    {

        cin >> Lessons[i];

        sum += Lessons[i];

        mx = max(mx, Lessons[i]);

    }

 

    // Parametric Search의 범위는 레슨을 끊을 길이이다.

    // 최소값은 주어진 레슨의 길이에서 가장 큰 값이고

    // 최대값은 주어진 레슨의 길이를 모두 더한 값이다.

    // 이를 바탕으로 결정 문제를 도출하면

    // '해당 크기로 등분하였을 때 M과 같은지'가 된다.

    int s = mx, e = sum;

    while (s < e)

    {

        int m = (s + e) >> 1;

        int cnt = GetCount(m);

        

        // M보다 많다면 길이가 너무 짧다는 뜻이므로

        if (cnt > M)

            // 시작 범위를 조정한다.

            s = m + 1;

        // M보다 같거나 크다면 길이가 충분하다는 뜻이므로

        else

            // 끝 범위를 조정한다.

            e = m;

    }

 

    cout << e;

}


  • C# 6.0


using System;

 

namespace Csharp

{

    class Program

    {

        static int N, M;

        static int[] Lessons;

 

        static void Main(string[] args)

        {

            var inputs = Console.ReadLine().Split();

            N = Convert.ToInt32(inputs[0]);

            M = Convert.ToInt32(inputs[1]);

 

            int mx = 0, sum = 0;

            Lessons = new int[N + 1];

            inputs = Console.ReadLine().Split();

            for (int i = 0; i < N; ++i)

            {

                Lessons[i] = Convert.ToInt32(inputs[i]);

                mx = Math.Max(mx, Lessons[i]);

                sum += Lessons[i];

            }

            

            int s = mx, e = sum;

            while (s < e)

            {

                int m = (s + e) >> 1;

                int count = GetCount(m);

                

                if (count > M)

                    s = m + 1;

                else

                    e = m;

            }

 

            Console.Write(e);

        }

 

        static int GetCount(int size)

        {

            int count = 0;

 

            int sum = 0;

            for (int i = 0; i < N; ++i)

            {

                sum += Lessons[i];

                if (sum == size || sum + Lessons[i + 1] > size)

                {

                    sum = 0;

                    ++count;

                }

            }

            if (sum != 0)

                ++count;

 

            return count;

        }

    }

}


  • Python 3


from sys import stdin

input = stdin.readline

 

def getCount(lst, size):

    count = 1

 

    s = 0

    for i in lst:

        if s + i > size:

            count += 1

            s = 0

        s += i

    

    return count

    

M = list(map(int, input().split()))[1]

lst = list(map(int, input().split()))

 

s, e = max(lst), sum(lst)

while s < e:

    m = (s + e) >> 1

    count = getCount(lst, m)

    if count > M:

        s = m + 1

    else:

 

        e = m

 

print(e)


복기

솔루션을 보지 않고 푼 첫 파라메트릭 탐색 문제다. 파라메트릭 탐색은 최적화 문제를 결정 문제로 바꾸는 것이다. 자세한 것은 여기에서 확인할 수 있다. 이번 문제를 통해서 Python3의 다양한 최적화 기법을 알아낼 수 있었다. (1) Unpack은 되도록 하지 않는다. 필요한 부분만 골라내는 것이 빠르다. 여기서는 N을 제외하였는데 이로인해 안했을 때보다 4ms를 줄일 수 있었다. (2) 한 줄에 같은 타입의 여러 값이 들어올 때는 map으로 객체화하는 것이 좋다. 이로인해 안했을 때보다 4ms를 줄일 수 있었다. (3) 모듈화 할 수 있는 부분은 모듈화 한다. 여기서는 주어진 크기로 몇 등분 할 수 있는지 찾는 로직을 getCount()로 모듈화 했는데 안했을 때보다 무려 2배를 줄일 수 있었다. (4) max()와 sum()은 생각보다 시간을 사용하지 않는다. 



'Outdated > Algorithm Solution' 카테고리의 다른 글

[BOJ] 1967번 트리의 지름  (0) 2020.03.09
[BOJ] 1012번 유기농 배추  (0) 2020.03.02
[BOJ] 1654번 랜선 자르기  (0) 2020.02.20
[BOJ] 1992번 쿼드트리  (0) 2020.02.15
[BOJ] 1629번 곱셈  (0) 2020.02.14