백준

[백준] 3090 차이를 최소로 [자바]

거북이같은곰 2022. 1. 25. 19:00

 


https://justicehui.github.io/coci/2019/01/13/BOJ3090/

 

백준3090 차이를 최소로

문제 링크 http://icpc.me/3090

justicehui.github.io

https://ghdic.github.io/ps/boj-3090/

 

백준 3090 차이를 최소로 풀이

너와 나의 차이

ghdic.github.io

https://www.acmicpc.net/board/view/32602

 

글 읽기 - 이분탐색에 대해 잘 아시는분 계신가요??

댓글을 작성하려면 로그인해야 합니다.

www.acmicpc.net

 


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {
	static int N,T;
	static int[] arr;
	static int[] result;
 	public static void main(String arg[]) throws IOException {
 		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
 		N = Integer.parseInt(st.nextToken());
 		T = Integer.parseInt(st.nextToken());
 		arr = new int[N];
 		result = new int[N];
 		int max = 0;
 		st = new StringTokenizer(br.readLine(), " ");
 		for(int i = 0; i < N; i++) {
 			int a = Integer.parseInt(st.nextToken());
 			arr[i] = a;
 		}
 		for(int i = 0; i < N-1; i++) {
 			int su = Math.abs(arr[i]-arr[i+1]);
 			max = Math.max(max, su);
 		}
 		int left = 0;
 		int right = max+1;
 		int [] temp = new int[N];
 		while(left != right) {
 			int mid = (left + right) / 2;
 			if(isPossible(mid)) {
 				right = mid;
 			}
 			else {
 				left = mid+1;
 			}
 		}
 		StringBuilder sb = new StringBuilder();
 		for(int i = 0; i < N; i++) {
 			sb.append(result[i]).append(' ');
 		}
 		System.out.println(sb);
 	}
 	static boolean isPossible(int n) {
 		//양방향으로 되는지 계산
 		int[] carr = new int[N];
 		long cnt = 0; // 더하는 과정에서 int범위를 초과할 수 있음
 		copy(carr);
 		for(int i = 0; i < N-1; i++) {
 			//-> 앞쪽의 배열은 바뀌면 안된다.
 			//같은 경우 따로 연산이 필요없음 클 경우 (4 2) 큰 수를 빼야하는데 앞쪽의 배열은 바뀌면 안됨
 			if(carr[i] + n < carr[i+1]) { //(앞쪽 배열이 작음) mid를 더한 값이 다음 배열보다 작으면 앞쪽배열에 mid를 더한 값으로 변경해줌 이 때 연산횟수는 기존 배열 - 바뀐 값 이다. 
 				cnt += carr[i+1] - (carr[i] + n);
 				carr[i+1] = carr[i] + n;
 			}
 		}
 		
 		for(int i = N-1; i > 0; i--) {
 			//<- 뒤쪽의 배열은 바뀌면 안된다. 
 			if(carr[i]+n < carr[i-1]) {//(뒤쪽 배열이 작음) (4 2) 뒤쪽의 배열은 바뀌면 안됨
 				cnt += carr[i-1] - (carr[i] + n);
 				carr[i-1] = carr[i] + n;
 			}
 		}
 		if(cnt > T) {
 			return false; //연산이 많다면 mid를 증가시켜준다.
 		}
 		else { //연산의 수가 <= T가 될 때까지 돌림 예제2 (4 2 3 7 6) n=2 - > 4 2 4 6 4 = 4번의 연산
 			for(int i = 0; i < N; i++) {
 				result[i] = carr[i];
 			}
 			return true;
 		}
 	}
 	static void copy(int[] arrtmp) {
 		for(int i = 0; i < N; i++) {
 			arrtmp[i] = arr[i];
 		}
 	}
}