최코딩의 개발

[백준] 1049번 본문

코딩테스트/백준

[백준] 1049번

seung_ho_choi.s 2024. 1. 22. 22:56
728x90

사이트

https://www.acmicpc.net/problem/1049

 

1049번: 기타줄

첫째 줄에 N과 M이 주어진다. N은 100보다 작거나 같은 자연수이고, M은 50보다 작거나 같은 자연수이다. 둘째 줄부터 M개의 줄에는 각 브랜드의 패키지 가격과 낱개의 가격이 공백으로 구분하여 주

www.acmicpc.net

 

 

문제 

 

분석

초반에 문제가 이해가 안되었지만 집중해서 읽으니 나름 쉬운 문제 였다. 

 

일단 요점을 파악해야된다. 

적어도 N개를 사기 위해!! 적어도!! 이 적어도라는 말이 중요하다. 

필자는 N개를 딱 맞춰서 그에 맞는 최소 비용인줄 알았으나 아니었다. 

즉 N개 이상이 되도 최소비용이면 된다는 것이다!! 

 

그럼 필자는 어떻게 해결했을까? 

sett = new int[m + m];
one = new int[m];

다음과 같이 배열을 만들었다.

sett는 6개 세트 배열이고 one 배열은 낱개이다.

근데 sett 만 크기를 곱하기 2배한 이유는 낱개를 6을 곱해서 똑같이 넣어주기 위함이다.

for (int i = 0; i < one.length; i++) {
    copy_one[i] = one[i];
    one[i] *= 6;
    sett[i + m] = one[i];
}

즉 이렇게 낱개도 6개를 곱해서 넣어주면 세트로 한방에 사는것이 더 최소일때도 있기 때문이다. (뒤에서 설명)

 

이젠 본론으로 들어가서 

Arrays.sort(copy_one);
Arrays.sort(sett);

낱개배열을 카피한 copy_one 배열과 sett(낱개* 6 포함) 배열을 오름차순으로 정렬했다. 

 

if (n < 7) {
    return Math.min(sett[0], copy_one[0] * n);
}

그 후 기타줄이 6개 이하면 if 문을 써서 6개 이하인것만 따로 로직을 만들었다. 

 

이것은 세트별로 사는게 낫나 아니면 낱개*기타줄(6개 이하만) 로만 사는게 낫나!! 

즉 6개 이하기 때문에 애초에 세트 vs 낱개*기타줄 구도로 된다!! 

 

int mok = n / 6;
int reminder = n % 6;

int result1 = sett[0] * (mok + 1);
int result2 = sett[0] * mok + copy_one[0] * reminder;

return Math.min(result1, result2);

 

다음은 7개 이상일때다! 

여기서 핵심은 기타줄이 10개일때 6으로 나누어 세트(6) 즉 몫과, 낱개 즉 나머지를 구하는것이다.

그럼 1 하고 4가 나올것이다. 

 

sett[0]은 애초에 세트하고 낱개*6해서 나온 결과들 중 젤 최솟값이 나온 값이다. 

즉 sett[0] 값이랑 mok+1해서 원래 고쳐야될 기타 줄 개수보다 개수의 최소 비용이랑(ex 지금 기타줄이 10개면 12개가 됨)

 

아님 기타줄 갯수랑 딱 맞춰서(세트 + 낱개) 계산할때 Math.min 함수를 써서 계산하면 끝이다!! 

 

여기서 후자 방법이 의문인게 만약 고쳐야될 기타수가 16이고 세트2 낱개4가 나올경우 

세트1 낱개10 으로 계산할 수 있지 않나? 라고 생각할 수 있는데 이것은 명백한 실수다.

왜냐하면 sett[] 배열에서 낱개*6도 포함시켰기 때문에 다 계산해서 나온 최솟값이기 때문에 

세트2 낱개4로 하는 것이 바람직하다.

세트1 낱개10 이렇게 하면 낱개가 최소일때만 가능하지 오리지널 세트가 최소일때는 나오지 않는다.

 

 

전체 코드

package greedy;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Greedy1049 {
    static int n;
    static int[] sett;
    static int[] one;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());

        sett = new int[m + m];
        one = new int[m];
        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            sett[i] = Integer.parseInt(st.nextToken());
            one[i] = Integer.parseInt(st.nextToken());
        }
        System.out.println(solution(m));
    }

    public static int solution(int m) {
        int[] copy_one = new int[m];
        for (int i = 0; i < one.length; i++) {
            copy_one[i] = one[i];
            one[i] *= 6;
            sett[i + m] = one[i];
        }
        Arrays.sort(copy_one);
        Arrays.sort(sett);

        if (n < 7) {
            return Math.min(sett[0], copy_one[0] * n);
        }

        int mok = n / 6;
        int reminder = n % 6;

        int result1 = sett[0] * (mok + 1);
        int result2 = sett[0] * mok + copy_one[0] * reminder;

        return Math.min(result1, result2);
    }
}

 

결과

느낀점

if문에서 따로 수학함수를 놓지 않아서 틀렸다... 

그치만 바로 인지하고 고쳤다. 

그다지 어렵진 않았지만 역시 그리디라 그런지 살짝 두려웠다... 

728x90

'코딩테스트 > 백준' 카테고리의 다른 글

[백준] 14888번  (1) 2024.02.10
[백준] 10819번  (0) 2024.02.01
[백준] 9095번  (0) 2023.11.17
[백준] 7576번  (0) 2023.11.10
[백준] 1213번  (0) 2023.10.31