https://www.acmicpc.net/problem/2805
2805번: 나무 자르기
첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000) 둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M보
www.acmicpc.net
코드설명
파라매트릭 서치 문제입니다.
각 탐색때마다, 잘라서 가져갈 수 있는 나무길이를 상근이가 가져갈 나무길이 M과 비교하여
상근이가 가져갈 나무길이보다 잘라놓은 나무길이가 더 작거나 같다면, start = middle + 1 처리를 통해 더 많이 자릅니다.
반면에, 상근이가 가져갈 나무길이 M보다 더 많다면, end = middle - 1 작업을 통해서 덜 자릅니다.
위의 과정을 반복하다보면, M과 같거나 가장 근접한 값으로 탐색하게 되고,
탐색을 진행하다보면, end가 줄어들면서 반복문이 끝이 나고, end를 출력하면 됩니다
if(treeLength >= M) { start = middle + 1; }else { end = middle - 1; }
또한 유의해야할점은,
단순히 문제조건에
- 첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000)
- 둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M보다 크거나 같기 때문에, 상근이는 집에 필요한 나무를 항상 가져갈 수 있다. 높이는 1,000,000,000보다 작거나 같은 양의 정수 또는 0이다.
여기서 단순히 각 자료형의 범위를 보면 아슬아슬하게 int 를 통과하는 조건을 확인했지만,.
나무를 잘라서 차이를 구할때는 합계산이 들어가기에 long을 써야 문제의 조건을 통과합니다.
절단기의 높이가 올라가면, 오히려 상근이가 가져가야할 나무의 길이가 줄어든다는점을 유의해야합니다.
코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; import java.util.StringTokenizer; public class Main { public static int N, M, K = 0; public static int[] arr; public static StringBuilder sb = new StringBuilder(); public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); M = Integer.parseInt(st.nextToken()); arr = new int[N]; int end = 0; st = new StringTokenizer(br.readLine()); for(int i=0;i<N;i++) { arr[i] = Integer.parseInt(st.nextToken()); end = Math.max(end, arr[i]); } paramatricSearch(0, end); } public static void paramatricSearch(long start, long end) { long left = start; long right = end; while(left <= right) { long middle = (left + right) / 2; //절단기에 설정할 높이. long sum = 0; for(int i=0;i<N;i++) { sum += (arr[i] - middle) > 0 ? arr[i] - middle : 0; } //만약 상근이가 가져가려고하는 나무의 길이 M미터보다 더 많이있다면, 절단기의 높이를 올려줘야합니다. if(sum >= M) { left = middle + 1; } else if(sum < M) { right = middle - 1; } } System.out.println(right); } }
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; public class Main { public static int N, M; public static long[] arr; public static long value = 0; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); M = Integer.parseInt(st.nextToken()); arr = new long[N]; st = new StringTokenizer(br.readLine()); for(int i=0;i<N;i++) { arr[i] = Integer.parseInt(st.nextToken()); value = Math.max(value , arr[i]); } paraMatricSearch(); } public static void paraMatricSearch() { long start = 0; long end = value; while(start <= end) { long middle = (start + end) / 2; long treeLength = 0; for(int i=0;i<N;i++) { long diff = arr[i] - middle; if(diff > 0) { treeLength += diff; } } // System.out.println(middle+" "+treeLength); if(treeLength >= M) { start = middle + 1; }else { end = middle - 1; } } System.out.println(end); } }
정답코드 3입니다.
package Main; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int C, N, H, W, K, M; public static int answer = 0; public static int[] arr; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); M = Integer.parseInt(st.nextToken()); st = new StringTokenizer(br.readLine()); arr = new int[N]; for(int i=0;i<N;i++) { arr[i] = Integer.parseInt(st.nextToken()); } System.out.println(optimize(0, 1000000001)); } public static boolean decision(int cutterHeight){ long ret = 0; for(int i=0;i<N; i++) { ret += (arr[i] - cutterHeight) > 0 ? arr[i] - cutterHeight : 0; } return ret >= M; } public static int optimize(int lo, int hi) { int left = lo; int right = hi; while(left + 1 < right) { int mid = (left + right) / 2; //만약 나무를 잘랐을떄, 원하는 값만큼 자를 수 있다면, 절단기의 높이를 증가시킵니다. if(decision(mid) == true) { left = mid; } else if(decision(mid) == false){ right = mid; } } return right - 1; } }
for문으로 처리해도 가능합니다. 100번의 이진탐색으로 원하는 값을 찾을 수 있습니다.
package Main; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int C, N, H, W, K, M; public static int answer = 0; public static int[] arr; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); M = Integer.parseInt(st.nextToken()); st = new StringTokenizer(br.readLine()); arr = new int[N]; for(int i=0;i<N;i++) { arr[i] = Integer.parseInt(st.nextToken()); } System.out.println(optimize(0, 1000000001)); } public static boolean decision(int cutterHeight){ long ret = 0; for(int i=0;i<N; i++) { ret += (arr[i] - cutterHeight) > 0 ? arr[i] - cutterHeight : 0; } return ret >= M; } public static int optimize(int lo, int hi) { int left = lo; int right = hi; for(int it = 0; it<100; it++) { int mid = (left + right) / 2; //만약 나무를 잘랐을떄, 원하는 값만큼 자를 수 있다면, 절단기의 높이를 증가시킵니다. if(decision(mid) == true) { left = mid; } else if(decision(mid) == false){ right = mid; } } return right - 1; } }
'알고리즘 > binary_search' 카테고리의 다른 글
[백준] 3079 입국심사 - 파라매트릭 서치(Paramatric Search) JAVA (0) | 2023.07.28 |
---|---|
[백준] 1654 랜선 자르기 - 파라매트릭 서치(Paramatric Search) JAVA (0) | 2023.07.28 |
[백준] 2512 예산 - 파라매트릭 서치(Paramatric Search) JAVA (0) | 2023.07.27 |
[백준] 19637 IF문 좀 대신 써줘 - 이분탐색(binary search) + 시간초과 JAVA (0) | 2023.07.27 |
[백준] 2512 예산 - 파라메트릭 서치(Paramatric Search) JAVA (0) | 2023.07.27 |