어렵다.
이진 탐색 문제는 원래 다 이렇게 어려운 걸까?
예전에 풀었던 문제인데 나중에 반드시 다시 풀어보겠다고 생각했고 그게 오늘이다.
오늘도 글 쓰면서 실시간으로 도전한다.
우선 문제를 읽고 조건을 정리해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// A = new int[N][N]
// A[i][j] = i*j
// 1차원 배열로 변경? B = new int[N*N];
// 예제 입력값 (3, 7)의 경우
// 1 2 3
// 2 4 6
// 3 6 9
// B[7] = 6
// 문제를 풀기 위한 조건들
// 1. B[x]는 x보다 작거나 같다.
// 2. B[x]에서 x는 B[x]보다 작거나 같은 수의 개수와 같다.
// 3. B[x]에서 x는 Math.min(B[x]를 1 ~ N까지수로 나눈 값, N)의 합과 같다.
// ( 3 + 3 + 1 )
|
cs |
이 문제의 난관은 2개다.
첫 번째는 이진 탐색으로 풀어야 한다는 사실과 그 방법을 추론하는 것.
두 번째는 Lower Bound.
Lower Bound는 모르면 따로 찾아보자.
난 둘 다 스스로 못해서 해설 보고 배웠었다.
ㅋㅋㅎ
우선 문제를 보고 도저히 알 수 없고, 예제가 간단하게 주어진 경우에는 예제를 적어보고 그 안에서 규칙성을 찾아내는 게 제일 효율적이다.
예제에서 입력값이 (3, 7)일 때 정답은 6이라고 한다.
입력값이 3인 경우는 아래와 같다.
1 2 3
2 4 6
3 6 9
엥 ? 구구단 표가 완성이 될 것 같은 행렬이다.
그리고 이걸 1차원 배열로 옮기면 이런 형태가 된다.
1 2 2 3 3 4 6 6 9
따라서 7번째 값은 6이 나오는데, 우리는 여기서 몇 가지를 알 수 있다.
1. B[x]는 반드시 x보다 작거나 같다.
숫자가 더 늘어나도 마찬가지다.
2. B[x]에서 x (몇 번째 수인지)는 B[x]보다 작거나 같다.
3. B[x]에서 x는
int answer = 0;
for (int i=0; i<N; i++) {
answer += Math.min(x/N, N)
}
과 같다.
즉, 임의 수를 놓고 answer가 m과 같아지는 경우를 찾아야하며
비교하는 범위는 최대 x와 같다는 것이다.
위 조건들을 전제로 문제를 풀어보자.
바로 야매 수도코드를 작성해보았다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
public class Main {
public static void main(String[] args) {
// A = new int[N][N]
// A[i][j] = i*j
// 1차원 배열로 변경? B = new int[N*N];
// 예제 입력값 (3, 7)의 경우
// 1 2 3
// 2 4 6
// 3 6 9
// B[7] = 6
// 문제를 풀기 위해 유추해내야 하는 조건들
// 1. B[x]는 x보다 작거나 같다.
// 2. B[x]에서 x는 B[x]보다 작거나 같은 수의 개수와 같다.
// 3. B[x]에서 x는 Math.min(B[x]를 1 ~ N까지수로 나눈 값, N)의 합과 같다.
// ( 3 + 3 + 1 )
// 배열 크기 N 입력 받기.
// 구해야하는 수 K 입력 받기.
// 바로 이진 탐색(N, K)
}
// 이진탐색 (배열 크기 N, 구해야하는 자리수 K)
// l = 1 (인덱스가 1부터 시작한다.)
// r = K (구해야하는 수 B[K]는 K보다 작거나 같다.)
// while (l<=r)
// m = (l+r) /2;
// 카운트 변수
//
// 반복문 ( N만큼 )
// {
// count += Math.min(m / N, N)
// }
//
// 만약 ( count가 m보다 크거나 같을 경우 ) l = m+1;
// 아니라면 r = m-1;
//
// 출력 l
}
|
cs |
방금 작성한 거라서 나도 맞는지 틀렸는지 모른다.
지금 풀어보고 오겠다.
전체적으로 맞았는데 중간에 말도 안되는 이상한 주석을 작성해놨다.
이진 탐색 안에..
문제를 풀기 위한 조건들을 이해했다면 어느 부분이 문제인지 찾아낼 수 있을 것이다.
근데 나만 이렇게 어려운 거 아니겠지?
유형 조금만 다르게 나와도 풀 자신 없음 ㅎㅎ
정답은 아래에.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// A = new int[N][N]
// A[i][j] = i*j
// 1차원 배열로 변경? B = new int[N*N];
// 예제 입력값 (3, 7)의 경우
// 1 2 3
// 2 4 6
// 3 6 9
// B[7] = 6
// 문제를 풀기 위해 유추해내야 하는 조건들
// 1. B[x]는 x보다 작거나 같다.
// 2. B[x]에서 x는 B[x]보다 작거나 같은 수의 개수와 같다.
// 3. B[x]에서 x는 Math.min(B[x]를 1 ~ N까지수로 나눈 값, N)의 합과 같다.
// ( 3 + 3 + 1 )
// 배열 크기 N 입력 받기.
int N = Integer.parseInt(br.readLine());
// 구해야하는 수 K 입력 받기.
int K = Integer.parseInt(br.readLine());
// 바로 이진 탐색(N, K)
binary_search(N, K);
}
// 이진탐색 (배열 크기 N, 구해야하는 자리수 K)
public static void binary_search(int n, int k) {
// l = 1 (인덱스가 1부터 시작한다.)
int l = 1;
// r = K (구해야하는 수 B[K]는 K보다 작거나 같다.)
int r = k;
while (l<=r) {
// while (l<=r)
// m = (l+r) /2;
int m = (l + r) / 2;
int count = 0;
// 카운트 변수
// 반복문 ( N만큼 )
for (int i = 1; i <= n; i++) {
// count += Math.min(m / N, N)
count += Math.min(m / i, n);
}
//
// 만약 ( count가 m보다 크거나 같을 경우 ) l = m+1;
if (count < k) l = m+1;
// 아니라면 r = m-1;
else r = m-1;
//
}
// 출력 l
System.out.println(l);
}
}
|
cs |
주석은 무시하자
'CS ﹒ Algorithm > Baekjoon' 카테고리의 다른 글
Java 백준 문제풀이 (58) 1744 _ 수 묶기 (0) | 2022.10.29 |
---|---|
Java 백준 문제풀이 (58) 1715 _ 카드 정렬하기 (0) | 2022.10.29 |
Java 백준 문제풀이 (56) 2343_ 기타 레슨 (0) | 2022.10.25 |
Java 백준 문제풀이 (55) 1167_트리의 지름 (0) | 2022.10.21 |
Java 백준 문제풀이 (54) 미로 탐색 (0) | 2022.10.15 |