BOJ_4384_공평하게 팀 나누기 (Java)
BOJ_4384_공평하게 팀 나누기 (Java)
[Gold I] 공평하게 팀 나누기 - 4384
성능 요약
메모리: 36892 KB, 시간: 188 ms
분류
다이나믹 프로그래밍, 배낭 문제
제출 일자
2025년 2월 10일 23:55:01
문제 설명
학생회장을 하고 있는 상근이는 이번 학교 축제 행사로 학우들간의 친밀감을 돈독히 하고자 줄다리기를 하려 한다.
하지만 이 줄다리기에 형평성을 최대한 고려하기위해 두 팀간의 사람 수 차이를 1 이하로 하려하며, 두 팀간의 몸무게의 차이가 최소화되도록 하고자 한다.
이때 상근이가 나누려 하는 두 팀의 몸무게를 각각 출력 하시오.
입력
가장 첫 번째 줄에 줄다리기를 하기 원하는 총 인원의 수(1 ≤ N ≤ 100)가 주어진다.
이후 N개의 줄에 줄다라기에 참여하기 원하는 사람의 몸무게(1 ≤ K ≤ 450)가 주어진다.
출력
두팀의 몸무게를 작은 순서대로 순차적으로 출력한다.
문제 풀이
각 사람(i)에 대해 두 가지 선택이 가능합니다
- 팀 A에 포함시키지 않는 경우 (팀 B에 포함)
- 팀 A에 포함시키는 경우
Math.abs(N/2 - (teamACnt[i-1][j-w[i]]+1))
: i번째 사람을 팀 A에 추가했을 때, 이상적인 팀 크기(N/2)와의 차이Math.abs(N/2 - teamACnt[i][j])
: 현재 상태에서 팀 A의 크기와 이상적인 팀 크기(N/2)와의 차이Math.abs((N-N/2) - (teamACnt[i-1][j-w[i]]+1))
: i번째 사람을 팀 A에 추가했을 때, 팀 A의 크기와 팀 B의 이상적인 크기(N-N/2)와의 차이Math.abs((N-N/2) - teamACnt[i][j])
: 현재 상태에서 팀 A의 크기와 팀 B의 이상적인 크기(N-N/2)와의 차이
즉, i번째 사람을 팀 A에 포함시키는 것이 전체적으로 더 균형 잡힌 팀 구성을 만드는 경우에만 이 상태를 선택합니다.
코드
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
package BOJ_4384_공평하게팀나누기;
/**
* Author: nowalex322, Kim HyeonJae
*/
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br;
static BufferedWriter bw;
static StringTokenizer st;
static int N, w[], totalW, teamACnt[][], gap = Integer.MAX_VALUE, finalA, finalB;
static boolean[][] dp;
public static void main(String[] args) throws Exception {
new Main().solution();
}
public void solution() throws Exception {
// br = new BufferedReader(new InputStreamReader(System.in));
br = new BufferedReader(new InputStreamReader(new FileInputStream("src/main/java/BOJ_4384_공평하게팀나누기/input.txt")));
bw = new BufferedWriter(new OutputStreamWriter(System.out));
N = Integer.parseInt(br.readLine());
w = new int[N+1];
for(int i = 1; i <= N; i++) {
w[i] = Integer.parseInt(br.readLine());
totalW += w[i];
}
dp = new boolean[N+1][totalW+1]; // dp[i][j]: i명까지 고려했을 때, 팀 A의 몸무게 합이 j가 되는 경우가 가능한지
teamACnt = new int[N+1][totalW+1]; // teamACnt[i][j]: i명까지 고려했을 때, 팀 A의 몸무게 합이 j일 때 팀 A에 속한 사람 수
dp[0][0] = true;
for (int i = 1; i <= N; i++) {
for(int j = 0; j <= totalW; j++) {
// 경우 1: i번째 사람을 팀 A에 포함시키지 않음
if(dp[i-1][j]) {
dp[i][j] = true;
teamACnt[i][j] = teamACnt[i-1][j];
}
// 경우 2: i번째 사람을 팀 A에 포함시킴
if(j-w[i]>=0 && dp[i-1][j-w[i]]) { // 더 균형잡힌 팀 구성도 고려해야함
if(Math.abs(N/2 - (teamACnt[i-1][j-w[i]]+1)) < Math.abs(N/2 - teamACnt[i][j])
&& Math.abs((N-N/2) - (teamACnt[i-1][j-w[i]]+1)) < Math.abs((N-N/2) - teamACnt[i][j])){
dp[i][j] = true;
teamACnt[i][j] = teamACnt[i-1][j-w[i]] +1;
}
}
}
}
for(int a_w = 1; a_w <= totalW; a_w++) {
// 팀 A의 인원수가 조건(N/2 또는 N-N/2)에 맞고, 해당 몸무게 조합이 가능한 경우
if((teamACnt[N][a_w] == N/2 || teamACnt[N][a_w] == (N - N/2))&& dp[N][a_w]){
if(Math.abs(a_w - (totalW - a_w)) < gap){
finalA = a_w;
finalB = totalW - a_w;
gap = Math.abs(a_w - (totalW - a_w));
}
}
}
if(finalA > finalB) {
int tmp = finalA;
finalA = finalB;
finalB = tmp;
}
bw.write(String.valueOf(finalA) + " " + finalB);
bw.flush();
bw.close();
br.close();
}
}
This post is licensed under
CC BY 4.0
by the author.