✏️ 문제 탐색
https://www.acmicpc.net/problem/2467
산성 용액(1~1,000,000,000 양의 정수)
알칼리성 용액(-1~-1,000,000,000 음의 정수)
N개의 용액 중 두 개의 서로 다른 용액의 합이 0에 가장 가깝게 만들려고 한다.
이때 두 용액을 출력하라.
✏️ 구현 아이디어
용액이 최대 100,000개일 때 그 중 2개의 용액을 선택하는 경우는 100,000_P_2 = 100,000*99,999이다.
모든 연산을 제한 시간(1초) 안에 수행할 수 없다.
따라서 용액 2가지를 찾을 때 이분 탐색을 사용해보자.
각 N개의 용액 마다 자신을 제외한 N-1개의 용액과 짝을 지은 후
합해서 0에 가장 가까운 값이 무엇인지 구한다.
예)
5
-99 -2 -1 4 98
N개의 용액이 이미 정렬되어있으므로 다시 정렬할 필요는 없음
-99에 대해서 합이 0과 가장 가까운 수가 뭔지 탐색해보자.
start=0, end=4, mid=2
-99+(-1)=-100
합이 음수이므로 범위를 뒤로 조정
start=3, end=4, mid=3
-99+4=-95
합이 음수이므로 범위를 뒤로 조정
start=4, end=4, mid=4
-99+98=1
합이 양수이므로 범위를 앞으로 조정
start=5, end=4, mid=4
start>end이므로 탐색 종료
나머지 -2, -1, 4, 98에 대해서도 탐색을 진행한다.
전체 탐색 과정에서 두 용액의 합의 절댓값이 minDist보다 작으면 minDist와 그 때 두 용액의 위치를 갱신한다.
마지막으로 저장된 두 용액의 위치를 이용해서 두 용액의 값을 출력한다.
✏️ 알고리즘
이분탐색
✏️ 시간 복잡도
용액이 최대 100,000개, 용액 마다 약 log100,000번 탐색하므로
총 100,000*5번 연산 -> 제한 시간(1초) 안에 탐색 가능하다.
✏️ 오답 노트
탐색 범위를 조정하는 조건을 '두 용액의 합이 양수인지/음수인지'가 아니라
'두 용액의 합이 0에서 더 멀어졌는지/가까워졌는지'로 두고 풀어서 틀렸다.
N개의 용액이 음수와 양수가 섞여있을 수도 있고, 음수 또는 양수로만 이루어져있을 수도 있어서
이분 탐색 시 하위 조건문으로 음수/양수를 나눠야 하나 생각했는데 아니었다.
✏️ 코드 설계
- 입력 받기 (용액의 특성값이 최대 1,000,000,000이 될 수 있으므로 long타입 사용)
- 현재까지 용액 합의 절댓값 중 가장 작은 값을 저장하는 minDist 선언
- minDist가 갱신될 때마다 두 용액의 위치가 어디인지 저장하는 ans[] 선언
- 0~N-1 용액 마다 이분 탐색 (start=i+1, end=N-1)
- mid, sum, dist를 계산
- sum이 양수이면 앞으로 범위 조정
- sum이 음수이면 뒤로 범위 조정
- minDist>dist이면 minDist, 두 용액의 위치 갱신
- 마지막으로 갱신된 두 용액의 특성값을 출력
✏️ 정답 코드
import java.io.*;
import java.util.*;
public class Main{
static int N;
static long[] liq;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
//입력 받기
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
liq = new long[N];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) {
liq[i] = Long.parseLong(st.nextToken());
}
long minDist = Long.MAX_VALUE;
int[] ans = new int[2];
for(int i=0; i<N-1; i++){
//0번째 용액부터 N-2번째 용액까지 탐색하며
//본인을 제외한 용액과의 합이 0과 가까운 용액이 무엇인지 찾기
int start = i+1;
int end = N-1;
while(start <= end){
int mid = (start+end)/2;
long dist = Math.abs(liq[mid] + liq[i]);
long sum = liq[mid] + liq[i];
if(dist < minDist){
minDist = dist;
ans[0] = i;
ans[1] = mid;
}
if(sum < 0){
//합이 음수면 뒤로 범위 조정
start = mid + 1;
}else{
//합이 양수면 앞으로 범위 조정
end = mid - 1;
}
}
}
Arrays.sort(ans);
System.out.println(liq[ans[0]] + " " + liq[ans[1]]);
}
}
'코테' 카테고리의 다른 글
| [백준/Java] 13702번 : 이상한 술집 (0) | 2025.01.23 |
|---|---|
| [백준/Java] 25418번 정수 a를 k로 만들기 (1) | 2025.01.22 |
| [백준/Java] 2805번 : 나무 자르기 (1) | 2025.01.20 |
| [백준/Java] 11663번 : 선분 위의 점 (1) | 2025.01.19 |
| [백준/Java] 17266번 : 어두운 굴다리 (2) | 2025.01.18 |