https://www.acmicpc.net/problem/1744
길이가 N인 수열이 주어졌을 때, 그 수열의 합을 구하려고 한다. 하지만, 그냥 그 수열의 합을 모두 더해서 구하는 것이 아니라, 수열의 두 수를 묶으려고 한다. 어떤 수를 묶으려고 할 때, 위치에 상관없이 묶을 수 있다. 하지만, 같은 위치에 있는 수(자기 자신)를 묶는 것은 불가능하다. 그리고 어떤 수를 묶게 되면, 수열의 합을 구할 때 묶은 수는 서로 곱한 후에 더한다.
예를 들면, 어떤 수열이 {0, 1, 2, 4, 3, 5}일 때, 그냥 이 수열의 합을 구하면 0+1+2+4+3+5 = 15이다. 하지만, 2와 3을 묶고, 4와 5를 묶게 되면, 0+1+(23)+(45) = 27이 되어 최대가 된다.
수열의 모든 수는 단 한번만 묶거나, 아니면 묶지 않아야한다.
수열이 주어졌을 때, 수열의 각 수를 적절히 묶었을 때, 그 합이 최대가 되게 하는 프로그램을 작성하시오.
첫째 줄에 수열의 크기 N이 주어진다. N은 50보다 작은 자연수이다. 둘째 줄부터 N개의 줄에 수열의 각 수가 주어진다. 수열의 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.
수를 합이 최대가 나오게 묶었을 때 합을 출력한다. 정답은 항상 231보다 작다.
이번 문제는 그리디 알고리즘이다. 그리디 알고리즘은 귀류법을 통해 증명을 해놓는 습관이 중요하다.
이번 문제는 숫자 배열을 곱하기로 묶어서 최대값을 구하는 문제이다. 내가 세운 가설은 다음과 같다.
양수 영역부터 명제를 확인해보자. 만약 양수 부분에서 내림차 순으로 2개씩 곱하지 않았을 때 최대값이 나온다면 내 명제는 틀린 것이다.
양수가 9, 8, 7, 6이 있을 때 2개씩 곱한 값으로 대체 할 수 있다면 이 제일 크다.
그런데 여기서 등 다르게 계산한 것은 모두 위에 계산보다 작을 것이므로 명제는 참이라 할 수 있다. 음수도 이와 마찬가지로 증명이 된다.
앞선 명제를 바탕으로 우선순위 큐를 활용해 계산을 하면 쉽게 해결할 수 있다!
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
PriorityQueue<Integer> pq1 = new PriorityQueue<>(Collections.reverseOrder());
PriorityQueue<Integer> pq2 = new PriorityQueue<>();
int count = 0;
for(int i = 0 ; i < N ; i++){
int value = Integer.parseInt(br.readLine());
if(value > 0){
pq1.offer(value);
}else if(value < 0){
pq2.offer(value);
}else{
count++;
}
}
int answer = 0;
while(pq1.size() > 1){
Integer first = pq1.poll();
Integer second = pq1.poll();
answer += Math.max(first * second , first + second);
}
if(!pq1.isEmpty()){
answer += pq1.poll();
}
while(pq2.size() > 1){
Integer first = pq2.poll();
Integer second = pq2.poll();
answer += Math.max(first * second , first + second);
}
if(!pq2.isEmpty()){
if(count == 0){
answer += pq2.poll();
}
}
System.out.println(answer);
}
}