[백준/Java] 1744

민선규·2023년 8월 30일

코딩테스트

목록 보기
16/20
post-thumbnail

수 묶기

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개씩 곱한 합과 양수의 개수가 홀수 일 경우 남은 값을 더한다.
  • 음수 영역은 오름차 순으로 2개씩 곱한 합과 만일 음수 영역의 값이 홀수 일 경우 0의 존재 유무를 확인해 존재한다면 그 음수를 음수0*0 으로 제거하고 없다면 음수를 더한다.

양수 영역부터 명제를 확인해보자. 만약 양수 부분에서 내림차 순으로 2개씩 곱하지 않았을 때 최대값이 나온다면 내 명제는 틀린 것이다.
양수가 9, 8, 7, 6이 있을 때 2개씩 곱한 값으로 대체 할 수 있다면 98+769*8 + 7*6이 제일 크다.
그런데 여기서 97+789*7 + 7*8 등 다르게 계산한 것은 모두 위에 계산보다 작을 것이므로 명제는 참이라 할 수 있다. 음수도 이와 마찬가지로 증명이 된다.

앞선 명제를 바탕으로 우선순위 큐를 활용해 계산을 하면 쉽게 해결할 수 있다!

풀이 코드

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);
    }
}

0개의 댓글