[白俊2805]木を切る
4889 ワード
[白俊2805]木を切る
第一の考え
木を降順に並べて、上から下へ削って、削った数まで数えます.
最大ツリー(0番インデックス)が最大ツリー(1番インデックス)より小さい場合、ターゲットインデックスは1増加します.
ターゲットインデックスが0でない場合、ターゲットインデックスのツリーが次のインデックスのツリーより大きい場合、ターゲットは0に戻ります.
任意の数のツリーが得られると、0番目のインデックスのツリー長はカッターの最小高さになります.
Java Code
package algo.study.thisweek;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.StringTokenizer;
public class Acmicpc_2805_나무자르기 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
int N = Integer.valueOf(st.nextToken()); // 나무의 수
int M = Integer.valueOf(st.nextToken()); // 최대 나무길이
Integer[] trees = new Integer[N];
st = new StringTokenizer(br.readLine(), " ");
for(int i=0; i<N; i++) {
trees[i] = Integer.valueOf(st.nextToken());
}
Arrays.sort(trees, Collections.reverseOrder());
int answer = 0;
int cnt = 0;
int pointer = 0;
if(N == 1) {
answer = trees[0] - M;
}else {
while(cnt < M) {
if(pointer == 0) {
if(trees[pointer] >= trees[pointer+1]) {
trees[pointer]--;
cnt++;
}else {
pointer++;
}
}else {
if(trees[pointer-1] < trees[pointer]) {
trees[pointer]--;
cnt++;
}else {
if(trees[pointer] < trees[pointer+1]) {
pointer++;
}else {
pointer = 0;
}
}
}
}
answer = trees[0];
}
System.out.println(answer);
}
}
タイムアウト
バイナリ・ナビゲーションによるアクセス
木を1本ずつ切り落とすのではなく、カッターの長さで二分探索.
中間値は、最も高いツリーに対してカッター高さ(mid)として初めて決定されます.
得られた値が多ければ等しい場合、startはmid+1に上昇する.
startが高いほど、カッターの高さが高くなり、得られる木の長さが短くなります.
得られた値が少なければendはmid−1に減少する.
バイナリサーチ
package algo.study.thisweek;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.StringTokenizer;
public class Acmicpc_2805_나무자르기 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
int N = Integer.valueOf(st.nextToken()); // 나무의 수
int M = Integer.valueOf(st.nextToken()); // 최대 나무길이
Integer[] trees = new Integer[N];
st = new StringTokenizer(br.readLine(), " ");
for(int i=0; i<N; i++) {
trees[i] = Integer.valueOf(st.nextToken());
}
Arrays.sort(trees, Collections.reverseOrder());
int answer = 0;
int cnt = 0;
int pointer = 0;
if(N == 1) {
answer = trees[0] - M;
}else {
while(cnt < M) {
if(pointer == 0) {
if(trees[pointer] >= trees[pointer+1]) {
trees[pointer]--;
cnt++;
}else {
pointer++;
}
}else {
if(trees[pointer-1] < trees[pointer]) {
trees[pointer]--;
cnt++;
}else {
if(trees[pointer] < trees[pointer+1]) {
pointer++;
}else {
pointer = 0;
}
}
}
}
answer = trees[0];
}
System.out.println(answer);
}
}
エラー
得られたツリーの長さはint範囲を超えることが多い.
成長金に両替して通過しました.
Java Code
package algo.study.thisweek;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Acmicpc_2805_나무자르기 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
int N = Integer.valueOf(st.nextToken()); // 나무의 수
int M = Integer.valueOf(st.nextToken()); // 최대 나무길이
int max = Integer.MIN_VALUE;
Integer[] trees = new Integer[N];
st = new StringTokenizer(br.readLine(), " ");
for(int i=0; i<N; i++) {
trees[i] = Integer.valueOf(st.nextToken());
if(trees[i] > max) max = trees[i];
}
int start = 0; // 절단기 높이 값찾기의 시작
int end = max; // 절단기의 최대 높이 = 나무의 최대 높이
int answer = 0;
while(start<=end) {
int mid = (start+end) / 2; // 중간값을 절단기의 높이로!
long sum = 0; // 얻어지는 나무길이
for(int i=0; i<N; i++) {
if(trees[i] > mid) {
sum += trees[i] - mid;
}
}
if(sum >= M) {
start = mid+1;
answer = mid;
}else {
end = mid-1;
}
}
System.out.println(answer);
}
}
正解
再帰二分ルックアップコード
static int[] list = {1, 3, 5, 7, 9, 11, 14, 15, 18, 19, 25, 28};
// mid = 찾을 값의 인덱스
int search(int start, int end, int target) {
if(start > end) return -1; //못찾음
int mid = (start + end) / 2;
if(list[mid] == target) return mid;
else if(list[mid] > target) return search(start, mid - 1, target);
else return search(mid + 1, end, target);
}
Reference
この問題について([白俊2805]木を切る), 我々は、より多くの情報をここで見つけました https://velog.io/@mulgyeol/백준-2805-나무자르기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol