smooth waters run deep

1d-1c/BOJ

2805_나무 자르기 (JAVA) (C++)

yeon_11 2020. 9. 18. 22:43
 

2805번: 나무 자르기

첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000) 둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M을

www.acmicpc.net

 

[C++]

#include <cstdio>
#include <algorithm> //sort
using namespace std;

int n, minlength;
int namu[1000001];

long long cal(int length){ //집에 가져가는 나무의 높이 계산
    long long result = 0;
    for(int i=0; i<n; i++){
        if(namu[i]>length)
            result += namu[i]-length;
    }
    return result;
}

int main(){
    scanf("%d %d", &n, &minlength);
    
    for(int i=0; i<n; i++){
        scanf("%d", &namu[i]);
    }
    sort(namu, namu+n); //오름차순 정렬
    
    int mid;
    int left = 0;
    int right = namu[n-1]; //입력받은 나무길이의 최대값
    int temp = 0;
    // 예)3 1\n 1 2 2 의 경우, left>right되어 while문이 끝난다.
    // 이때, 마지막 mid값이 정답이 되므로 temp에 저장한다.

    while(left<=right){
        mid = (left+right)/2;
        long long x = cal(mid);

        if(x > minlength){
            temp = mid; //left>right 되었을 때를 대비해 저장
            left = mid+1;
        }
        else if(x < minlength)
            right = mid-1;
        else{
            printf("%d", mid);
            return 0;
        }
    }

    printf("%d", temp);
    
    return 0;
}

이분탐색 문제! 왜냐면 자료에서 특정값을 찾아야하고, 그 값을 예측하며 찾아야되니까

 

0 ~ namu[]배열의 최대값 사이의 숫자 중에서 '절단할 나무의 높이'를 찾는 것을 이분탐색으로 구현했다.

이를 위해 범위의 최소값(left)는 0, 최대값(right)은 입력받은 나무길이의 최대값인 namu[n-1]로 설정한다.

 

** 집에 가져가는 절단된 나무의 높이를 계산하는 cal()함수의 리턴값은 long long형을 사용해야 한다.

(int형으로 제출하면 시작하자마자 틀렸습니다 뜸!!)

 

 

 

 

[JAVA]

import java.util.Scanner;
import java.util.Arrays;

public class Main {
	static int N, M;
	static int[] namu;

	public static void main(String[] args) {
    	Scanner sc = new Scanner(System.in);
		N = sc.nextInt(); M = sc.nextInt();
		namu = new int[N];
		for(int i=0; i<N; i++){
			namu[i] = sc.nextInt();
			total += namu[i];
		}
		Arrays.sort(namu);

		//무엇을 찾을 것인가? 절단기에 설정하는 높이
		//범위 기준: 집에 가져갈 수 있는 나무의 길이
		int left = 1; //범위 최소
		int right = namu[N-1]; //범위 최대
		while(left<=right){
			int temp = 0;
			int mid = (left+right)/2; //찾으려는 값
			for(int i=0; i<N; i++){
				if(mid<namu[i])
					temp += (namu[i]-mid);
			}

			if(temp < M){ //M보다 작으면- 높이를 줄여야함
				right = mid-1;
			}
			else{
				left = mid+1;
			}
		}
		System.out.println(right);
    }

}

 

1. 무엇을 찾을 것인가? - 절단기에 설정할 나무의 높이

2. '절단기에 설정할 나무의 높이' 의 범위는?

    문제에서 1 ≤ M ≤ 2,000,000,000 이렇게 M의 범위를 주어졌으므로, '절단기에 설정할 나무의 높이' 최소 범위는 1

    최대 범위는 namu[]에서 가장 큰 값 (이거보다 더 큰값은 해당X. 문제에서 M의 최소값을 원했으니까)

3. 집에 가져갈 수 있는 나무의 길이 temp를 M을 기준으로 크고 작음을 판단한다.

    만약 temp가 M보다 작다면, '절단기에 설정할 나무의 높이'를 줄여야 한다.  : right = mid-1;

    M보다 크다면, '절단기에 설정할 나무의 높이'를 늘려야 한다.  : left = mid+1;

4. '절단기에 설정할 나무의 높이'의 최댓값을 구해야 하므로, right이 답이다.

'1d-1c > BOJ' 카테고리의 다른 글

11729_하노이 탑 이동 순서 (JAVA)  (0) 2020.10.02
10815_숫자 카드 (JAVA)  (0) 2020.09.18
1920_수 찾기 (JAVA) (C++)  (0) 2020.09.15
2343_기타 레슨 (JAVA)  (0) 2020.09.15
1012_유기농 배추 (JAVA)  (0) 2020.09.11