오늘은 수 묶기 문제다.
해당 유형의 문제는 모두 푸는 방법이 비슷하기 때문에, 하나만 혼자서 풀 수 있으면 나머지도 다 풀 수 있다.
우선 문제 조건을 정리하고 주석을 작성해보자.
1
2
3
4
5
6
7
8
9
10
|
// 수열의 합, but 최대 2개의 수끼리 묶어 곱한 뒤 더할 수 있음
// ex ) { 0, 1, 2, 3, 4, 5 } ?
// => 0 + 1 + ( 2 * 3 ) + ( 4 * 5 ) == 최대값
// 1. 큰 수끼리 곱하면 좋다.
// 2. 0은 곱하면 안된다.
// 3. 우선순위 큐를 쓰면 편하겠네요.
// 4. 정답이 항상 2^31보다 작다고 한다.. long 쓰자..
// 5. 문제는 음수다. 음수 양수를 따로 저장해야할 듯
// 6. 음수의 경우 -> (절대값 기준)큰 수끼리 곱하면 좋다. 0이랑 곱해도 좋다.
|
cs |
수열에서 값을 두 개씩 묶거나 묶지 않은 상태로 곱한 뒤 더할 수 있다고 한다.
1. 큰 수끼리 곱했을 때 당연히 더 큰 값이 나온다.
2. 정수에 0을 곱하면 손해니까 곱하면 안된다.
3. 늘 그렇듯 우선순위 큐를 쓰는 게 가장 깔끔한 방법이다.
4. int의 범위가 2^31이라서 문제가 없을 것 같지만 찝찝하니까 난 long을 쓰겠다. 바꾸기 귀찮잖아요.
5. 근데 음수는 어떡하지? 음수는 오히려 작은 수끼리 곱하면 더 큰 값이 나오는데요.
6. 따라서 음수와 0은 별도의 우선순위큐에 넣는다.
=>
예를 들어 { 3, 2, 0, -2, -3, -4}인 경우
3과 2는 당연히 곱하는 게 좋다.
0은 더해도 아무 이득이 없고 곱하면 손해다, 얘는 음수랑 곱해서 음수 하나를 제거해버리는 것이 이득이다.
-3과 -4는 곱하면 12가 되므로 곱하면 좋다.
이제 위의 조건을 바탕으로 야매 수도코드를 작성해보자.
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
|
public class Main {
public static void main(String[] args) throws Exception {
// 수열의 합, but 최대 2개의 수끼리 묶어 곱한 뒤 더할 수 있음
// ex ) { 0, 1, 2, 3, 4, 5 } ?
// => 0 + 1 + ( 2 * 3 ) + ( 4 * 5 ) == 최대값
// 1. 큰 수끼리 곱하면 좋다.
// 2. 0은 곱하면 안된다.
// 3. 우선순위 큐를 쓰면 편하겠네요.
// 4. 정답이 항상 2^31보다 작다고 한다.. long 쓰자..
// 5. 문제는 음수다. 음수 양수를 따로 저장해야할 듯
// 6. 음수의 경우 -> (절대값 기준)큰 수끼리 곱하면 좋다. 0이랑 곱해도 좋다.
// 수열 크기 N
// 우선순위 큐 생성
// 음수 우선순위 큐 생성
// 반복문 ( i < N )
// 우선순위 큐에 수열 입력 받기
// 만약 0 혹은 음수라면
// 음수 우선순위 큐에 수열 입력 받기
// int answer = greedy(양수 큐, 음수 큐)
// 정답 출력
public static long greedy(Queue<Integer> positive, Queue<Integer> negative) {
// 양수 결과 변수 p
// 음수 결과 변수 n
// while(positive.size > 0)
// num1 = positive.poll()
// 만약 다음 수가 없다면 p+=num1
// 아니라면 p += (num1*num2)
// while(negative.size > 0)
// num1 = negative.poll()
// 만약 다음 수가 없다면 n+=num1
// 아니라면 n += (num1*num2)
// 반환 p + n;
}
}
|
cs |
맞았을까요 틀렸을까요.
나도 아직 안 풀어봐서 모른다.
근데 일단 주석만 봐도 마음에 안 드는 부분이, greedy 메서드에 중복 코드가 발생하고 있다.
불쾌하기 때문에 저 부분은 변경이 필요하다.
.
.
아니나 다를까 틀렸다.
큰 틀에서 잘못된 부분은 없으나 특정 경우의 수를 생각해보면 뭔가 잘못됐다는 사실을 알 수 있다.
숫자 하나만 생각하면 되는 거니까 직접 생각해보자.
정답은 아래에.
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
public class Main {
public static void main(String[] args) throws Exception {
// 수열의 합, but 최대 2개의 수끼리 묶어 곱한 뒤 더할 수 있음
// ex ) { 0, 1, 2, 3, 4, 5 } ?
// => 0 + 1 + ( 2 * 3 ) + ( 4 * 5 ) == 최대값
// 1. 큰 수끼리 곱하면 좋다.
// 2. 0은 곱하면 안된다.
// 3. 우선순위 큐를 쓰면 편하겠네요.
// 4. 정답이 항상 2^31보다 작다고 한다.. long 쓰자..
// 5. 문제는 음수다. 음수 양수를 따로 저장해야할 듯
// 6. 음수의 경우 -> (절대값 기준)큰 수끼리 곱하면 좋다. 0이랑 곱해도 좋다.
// 수열 크기 N
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
// 우선순위 큐 생성
Queue<Integer> positive = new PriorityQueue<>((n1, n2) -> n2 - n1);
// 음수 우선순위 큐 생성 (기준 변경 필요)
Queue<Integer> negative = new PriorityQueue<>((n1, n2) -> n1 - n2);
int answer = 0;
// 반복문 ( i < N )
for (int i = 0; i < N; i++) {
int n = Integer.parseInt(br.readLine());
if (n == 1) {
answer += n;
}
else if (n > 0) {
// 우선순위 큐에 수열 입력 받기
positive.add(n);
} else {
// 만약 0 혹은 음수라면
// 음수 우선순위 큐에 수열 입력 받기
negative.add(n);
}
}
// int answer = greedy(양수 큐, 음수 큐)
long positiveResult = getSum(positive);
long negativeResult = getSum(negative);
answer += (positiveResult + negativeResult);
// 정답 출력
System.out.println(answer);
}
public static long getSum(Queue<Integer> queue) {
// 양수 결과 변수 p
// 음수 결과 변수 n
long p = 0;
// while(positive.size > 0)
while (queue.size() > 0) {
// num1 = positive.poll()
int num1 = queue.poll();
// 만약 다음 수가 없다면 p+=num1
if (queue.isEmpty()) {
p += num1;
} else {
// 아니라면 p += (num1*num2)
int num2 = queue.poll();
p += (num1 * num2);
}
}
// while(negative.size > 0)
// num1 = negative.poll()
// 만약 다음 수가 없다면 n+=num1
// 아니라면 n += (num1*num2)
// 반환 p + n;
return p;
}
}
|
cs |
늘 그렇듯 주석은 무시하자.
'CS ﹒ Algorithm > Baekjoon' 카테고리의 다른 글
Java 백준 문제풀이 (60) 1541_잃어버린 괄호 (0) | 2022.11.03 |
---|---|
Java 백준 문제풀이 (59) 1931 _ 회의실 배정 (0) | 2022.11.02 |
Java 백준 문제풀이 (58) 1715 _ 카드 정렬하기 (0) | 2022.10.29 |
Java 백준 문제풀이 (57) 1300 _ K번째 수 (0) | 2022.10.27 |
Java 백준 문제풀이 (56) 2343_ 기타 레슨 (0) | 2022.10.25 |