본문 바로가기
알고리즘/코딩 테스트 문제

[백준] 1654번 랜선 자르기(Java)

by 진진리 2024. 3. 8.
728x90

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

 

1654번: 랜선 자르기

첫째 줄에는 오영식이 이미 가지고 있는 랜선의 개수 K, 그리고 필요한 랜선의 개수 N이 입력된다. K는 1이상 10,000이하의 정수이고, N은 1이상 1,000,000이하의 정수이다. 그리고 항상 K ≦ N 이다. 그

www.acmicpc.net

 

처음에는 주어진 랜선의 길이를 모두 더하고 필요한 개수로 나눈 후 1씩 감소하면서 필요한 개수 이상의 랜선이 나오게 되면 반복문을 나와 출력하도록 코드를 작성하였다.

 

import java.io.*;
import java.util.*;

public class Main {
    static int stoi(String s) {
        return Integer.parseInt(s);
    }

    static int N;
    static int M;

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

        N = stoi(st.nextToken());
        M = stoi(st.nextToken());

        int[] arr = new int[N];
        long sum = 0;

        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            arr[i] = stoi(st.nextToken());
            sum += arr[i];
        }

        long length = sum / M;
        while(true) {
            long num = 0;
            for (int i = 0; i < N; i++) {
                num += arr[i]/length;
                if(num >= M) break;
            }
            if(num >= M) break;
            length--;
        }

        System.out.println(length);
    }
}

 

시간초과가 발생하였고 해당 문제의 알고리즘 분류가 이진 탐색이어서 공부해보았다.

 

이진 탐색(Binary Search)

앞에서는 문제 조건을 충족하는 길이를 찾기 위해 i--를 해주었다.

1씩 빼면서 답을 찾는 경우 속도가 느리기 때문에 이진 탐색을 사용하면 원하는 값을 더 빠르게 찾을 수 있다.

 

  • 오름차순 혹은 내림차순으로 정렬된 배열에 적용 가능한 탐색 기법
  • 시작점과 끝점 사이의 중앙값이 탐색값보다 작은 경우
    • 끝점을 중앙값으로 업데이트한다.
  • 시작점과 끝점 사이의 중앙값이 탐색값보다 큰 경우
    • 시작점을 중앙값으로 업데이트한다.

 

lower bound, upper bound?

  • 오름차순으로 정렬된 배열에서 탐색값이 여러 개인 경우, 
  • lower bound: 가장 앞에 있는 탐색값
  • upper bound: 탐색값 다음 위치의 값

 

위의 문제에서는 가능한 길이의 최대값을 구해야 하기 때문에 upper bound를 사용해야 한다.

import java.io.*;
import java.util.*;

public class Main {
    static int stoi(String s) {
        return Integer.parseInt(s);
    }

    static int N;
    static int M;
    static int[] arr;
    static long min = 1;

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

        N = stoi(st.nextToken());
        M = stoi(st.nextToken());

        arr = new int[N];
        long max = 0;

        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            arr[i] = stoi(st.nextToken());
            if(max < arr[i]) max = arr[i];
        }

        binarySearch(max+1);

        System.out.println(min-1);
    }

    public static void binarySearch(long max) {
        if(min >= max) return;
        long mid = (min + max) / 2;
        long count = 0;
        for (int i = 0; i < N; i++) {
            count += arr[i] / mid;
        }

        if(count < M) {
            binarySearch(mid);
        }
        else {
            min = mid+1;
            binarySearch(max);
        }
    }
}

 

max값에 +1을 해줘야 한다.

 

 

참고

https://charles098.tistory.com/133

 

[ 알고리즘 ] 이분탐색(Binary Search), upper_bound, lower_bound (C++)

1. 이분탐색 원리 이분탐색은 오름차순 또는 내림차순으로 정렬된 배열에 적용 가능한 탐색 기법이다. 정렬된 배열에서 특정 값을 찾을 때 정중앙에 위치한 값을 활용하면 아주 빠른 속도로 탐

charles098.tistory.com

https://st-lab.tistory.com/269

 

[백준] 1654번 : 랜선 자르기 - JAVA [자바]

https://www.acmicpc.net/problem/1654 1654번: 랜선 자르기 첫째 줄에는 오영식이 이미 가지고 있는 랜선의 개수 K, 그리고 필요한 랜선의 개수 N이 입력된다. K는 1이상 10,000이하의 정수이고, N은 1이상 1,000,0

st-lab.tistory.com