일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 알고리즘
- JPQL
- 인프런
- Proxy
- AOP
- Android
- 스프링 핵심 기능
- 스프링 핵심 원리
- 백준
- db
- SpringBoot
- Thymeleaf
- jpa
- JDBC
- QueryDSL
- Greedy
- 김영한
- springdatajpa
- java
- Servlet
- Exception
- http
- spring
- pointcut
- 그리디
- 스프링
- transaction
- 자바
- Spring Boot
- kotlin
- Today
- Total
개발자되기 프로젝트
[백준] Greedy: 수 묶기 본문
문제
길이가 N인 수열이 주어졌을 때, 그 수열의 합을 구하려고 한다. 하지만, 그냥 그 수열의 합을 모두 더해서 구하는 것이 아니라, 수열의 두 수를 묶으려고 한다. 어떤 수를 묶으려고 할 때, 위치에 상관없이 묶을 수 있다. 하지만, 같은 위치에 있는 수(자기 자신)를 묶는 것은 불가능하다. 그리고 어떤 수를 묶게 되면, 수열의 합을 구할 때 묶은 수는 서로 곱한 후에 더한다.
예를 들면, 어떤 수열이 {0, 1, 2, 4, 3, 5}일 때, 그냥 이 수열의 합을 구하면 0+1+2+4+3+5 = 15이다. 하지만, 2와 3을 묶고, 4와 5를 묶게 되면, 0+1+(2*3)+(4*5) = 27이 되어 최대가 된다.
수열의 모든 수는 단 한번만 묶거나, 아니면 묶지 않아야한다.
수열이 주어졌을 때, 수열의 각 수를 적절히 묶었을 때, 그 합이 최대가 되게 하는 프로그램을 작성하시오.
입력
첫째 줄에 수열의 크기 N이 주어진다. N은 50보다 작은 자연수이다. 둘째 줄부터 N개의 줄에 수열의 각 수가 주어진다. 수열의 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.
출력
수를 합이 최대가 나오게 묶었을 때 합을 출력한다. 정답은 항상 231보다 작다.
문제 접근
주어진 수열에서 중복되지 않게 임의의 두 수를 묶어서 곱할 수 있을 때, 가장 큰 합을 반환해야 한다.\
합이 가장 크도록 만들기 위해서는 양수인 경우 가장 큰 수들 끼리 곱해야 하고, 음수인 경우 가장 작은 수 끼리 곱해야 한다.
그럼 여기서 두 가지 방법이 있을 수 있다.
1. 한 배열에 모든 수를 넣고 정렬한 뒤 두 개의 인덱스를 활용해서 탐색하며 합을 구하는 방법
2. 양수, 음수, 0 모두 다른 배열에 넣어놓고 정렬한 후 각 배열마다 탐색 및 합 구하기.
1번의 경우 반복문 한 번으로 끝낼 수 있다. 하지만 0이 있는지 없는지 있으면 0의 위치를 알아야 하고, 양수 or 음수의 개수가 짝수일 때 홀수일 때 경우를 나누기 불편하다. 1번으로 작성하다가 if문만 계속 늘어나서 중단했다.
2번의 경우 상대적으로 간단하다. 양수, 음수, 0으로 나누고 양수, 음수에서 최대값을 단순히 뽑아내면 된다.
양수인 경우 내림차순으로 정렬한 뒤, 반복문을 돌면서 두 개씩 곱해주면 된다. 이 때 개수가 짝수&홀수인 경우를 주의.
또한 1을 만나는 경우 곱하는 것 보다 더하는게 이득이다. Math.max(곱, 합)으로 처리해 줬다. 또는 직접 1인지 판단해도 가능.
음수인 경우 오름차순으로 정렬한 뒤, 두 개씩 곱해주면 된다.
이때 마지막 음수를 따로 보관하자. 왜냐하면 0이 있을 경우 마지막 음수는 0으로 처리가 가능하다.
이 때 양수, 음수 모두 개수가 1개일 경우 처리할 수 있도록 로직이 필요하다.
풀이 코드
package baekjun;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
public class _1744 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
ArrayList<Long> overZero = new ArrayList<>();
ArrayList<Long> underZero = new ArrayList<>();
int zero = 0;
long answer = 0;
for (int i=0; i<N; i++){
long n = Long.parseLong(br.readLine());
if (n > 0){
overZero.add(n);
}else if (n < 0){
underZero.add(n);
}else {
zero++;
}
}
long sumPlus = 0;
overZero.sort(Collections.reverseOrder());
for (int i=0; i< overZero.size() ; i+=2){
if (overZero.size() == 1 && i == 0){
sumPlus += overZero.get(i);
}else if (i == overZero.size()-1){
sumPlus+= overZero.get(i);
}else {
sumPlus += Math.max(overZero.get(i)*overZero.get(i+1), overZero.get(i)+overZero.get(i+1));
}
}
long sumMinus = 0;
underZero.sort((n1, n2)-> (int) (n1-n2)); //오름차순
long tmp = 0; // 음수가 한개 남으면 잠시 보관, 0이랑 곱할 수 있음.
for (int i=0; i< underZero.size() ; i+=2){
if (i == underZero.size()-1){ //size가 1인 경우 바로 tmp에 저장하고 루프 나감.
tmp = underZero.get(i);
} else{
sumMinus += underZero.get(i)*underZero.get(i+1);
}
}
if (zero == 0){
answer = sumPlus + sumMinus + tmp;
}else{
//0이 존재하는 경우
//음수의 개수가 2개 이상인 경우 마지막 수(tmp)제외하고 sumMinus에 반영됨, 마지막수(tmp)는 0과 곱해져서 무의미
//음수의 개수가 1개인 경우, tmp에 저장되고 0과 곱해짐.
//음수의 개수가 0개이 경우, sumMinus = 0
answer = sumPlus + (underZero.size() > 1 ? sumMinus : 0);
}
System.out.println(answer);
}
}
'코테준비' 카테고리의 다른 글
[백준] Greedy: 행렬 (0) | 2022.06.01 |
---|---|
[백준] Greedy: 5와 6 의 차이 (0) | 2022.06.01 |
[백준] Greedy: 기타줄 (0) | 2022.05.30 |
[백준]Greedy: 보석도둑 (0) | 2022.05.29 |
[백준] Greedy: 캠핑 (0) | 2022.05.28 |