Baekjoon 3151 - 합이 0 (클릭 시 이동)
문제
Elly는 예상치 못하게 프로그래밍 대회를 준비하는 학생들을 가르칠 위기에 처했다. 대회는 정확히 3명으로 구성된 팀만 참가가 가능하다. 그러나 그녀가 가르칠 학생들에게는 큰 문제가 있었다. 코딩 실력이 좋으면 팀워크가 떨어지고, 팀워크가 좋을수록 코딩 실력이 떨어진다. 그리고 출전하고자 하는 대회는 코딩 실력과 팀워크 모두가 중요하다.
Elly는 그녀가 가르칠 수 있는 모든 학생들의 코딩 실력을 알고 있다. 각각의 코딩 실력 Ai는 -10000부터 10000 사이의 정수로 표시되어 있다. 그녀는 팀워크와 코딩 실력이 모두 적절한 팀을 만들기 위해, 세 팀원의 코딩 실력의 합이 0이 되는 팀을 만들고자 한다. 이러한 조건 하에, 그녀가 대회에 출전할 수 있는 팀을 얼마나 많이 만들 수 있는지를 계산하여라.
N명의 학생들의 코딩 실력 Ai가 -10000부터 10000사이의 정수로 주어질 때, 합이 0이 되는 3인조를 만들 수 있는 경우의 수를 구하여라.
시간 제한 | 메모리 제한 | 제출 | 정답 | 맞힌 사람 | 정답 비율 |
---|---|---|---|---|---|
4 초 | 128 MB | 1635 | 369 | 223 | 21.401% |
입력
입력은 표준 입력으로 주어진다.
첫 번째 줄에 학생의 수 N이 입력된다. 두 번째 줄에 N개의 그녀가 가르칠 학생들의 코딩 실력인 Ai가 주어진다.
출력
표준 출력으로 그녀가 고를 수 있는 팀의 수를 하나의 정수로 출력한다.
풀이
최대 경우의 수가 존재할 때는 N 이 10000이고 배열이 모두 0으로 주어진 경우이다.
이 때 경우의 수는 10000C3 = 166,616,670,000이므로 long타입으로 정답을 출력해야 한다.
- 입력값을 오름차순으로 정렬한다.
- 가장 작은 값(0번 인덱스)을 fix 시키고 1번인덱스와 마지막 인덱스를 start, end로 놓는다.
- 배열의 0, start, end의 값이 0인지 확인한다
- 합이 0보다 크면 end를 줄인다, 0보다 작거나 같으면 start를 늘린다.
효율 고려
같은 값이 존재할 수 있다. 만약 [-8, -2, -2, -2, 10, 10, 10, 10 ] 이라는 배열이 존재한다고 가정해 보자.
만들어 질 수 있는 부분집합은 {-8, -2, 10}밖에 존재하지 않지만 각각의 인덱스는 다른 경우가 된다.
따라서 -2의 갯수인 3과 10의 갯수인 4를 곱한 12가지의 경우가 존재한다.
또는 [-10, 5, 5, 5, 5, 5, 5, 5]라는 배열이 주어진다면 -10이 fix 되어 있을 때 start와 end가 가리키는 배열의 값은 같고 세개의 수의 합은 0이 된다. 이 때 경우의 수를 구하는 과정은 아래와 같다.
if(합 == 0){
if(data[start] == data[end]){
answer += comb(end-start-1); // nC2
}
}
static int comb(int n) {
return n * (n - 1) / 2;
}
최종 소스코드
import java.io.*;
import java.util.*;
public class Main {
static int N;
static long answer = 0L;
static int[] data;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = null;
N = Integer.parseInt(br.readLine());
data = new int[N];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) {
data[i] = Integer.parseInt(st.nextToken());
}
Arrays.sort(data);
for (int i = 0; i < N; i++) {
if (data[i] > 0) break;
int start = i + 1;
int end = N - 1;
while (start < end) {
int s = 1;
int e = 1;
int current = data[i] + data[start] + data[end];
if (current == 0) {
if (data[start] == data[end]) { // start == end일 경우
answer += comb(end - start + 1);
break;
}
// start의 다음 값이 같은 경우
while (start + 1 < end && data[start] == data[start + 1]) {
s++;
start++;
}
// end의 다음 값이 같은 경우
while (start < end - 1 && data[end] == data[end - 1]) {
e++;
end--;
}
answer += s * e;
}
if (current > 0)
end--;
else start++;
}
}
System.out.println(answer);
}
static int comb(int n) {
return n * (n - 1) / 2;
}
}
'Algorithm > BaekJoon' 카테고리의 다른 글
[백준] 16945번 - 움직이는 미로 탈출 (java) (0) | 2022.01.23 |
---|---|
[백준] 17836번 - 공주님을 구하라! (java) (0) | 2022.01.16 |
[백준] 11000번 - 강의실 배정 (java) (0) | 2022.01.12 |
[백준] 12919번 - A와 B 2 (java) (0) | 2022.01.12 |
[백준] 22942번 - 데이터 체커 (java) (0) | 2022.01.08 |