알고리즘/문제풀이
[백준 17610번] 양팔저울
Ohnim · 오님
2024. 8. 10. 19:03
문제 링크
https://www.acmicpc.net/problem/17610
문제 요약
이 문제는 서로 다른 무게의 추 \(k\) 개가 주어졌을 때, 양팔저울을 한 번만 사용하여 1부터 주어진 추들의 무게의 합인 \(S\) 사이의 모든 무게 중 측정이 불가능한 무게의 개수를 구하는 문제이다.
문제 풀이
이 문제를 해결하기 위해서는 \(k\)개의 추를 가지고 만들 수 있는 모든 가능한 무게 조합을 고려하는 완전 탐색을 이용할 수 있다. 각 추에 대해 우리는 세 가지 선택을 할 수 있다.
- 추를 사용하지 않는 경우
- 양팔저울의 왼쪽에 올려놓는 경우
- 양팔저울의 오른쪽에 올려놓는 경우
각 추를 위와 같은 세 가지 선택지 중 하나로 결정한 후, 양팔저울의 왼쪽과 오른쪽에 놓인 추들의 무게 차이를 계산한다. 이렇게 계산된 모든 가능한 무게를 boolean 배열에 기록한다. 이 배열은 특정 무게가 측정 가능한지 여부를 나타내는 배열이다. 마지막으로, 1부터 주어진 추들의 무게의 합인 \(S\)까지의 모든 무게를 순회하면서 boolean 배열에 기록되지 않은 무게의 수를 세면, 그 값이 바로 측정 불가능한 무게의 개수가 된다.
이 방법은 모든 경우의 수를 탐색하기 때문에 \(\mathcal {O}(3^k)\)의 시간복잡도를 가진다. 하지만 \(k\)가 최대 13밖에 되지 않기 때문에, 전체 경우의 수가 크지 않아 충분히 계산이 가능하다. 또한, 주어진 추들의 무게 합 \(S\)도 크지 않기 때문에 boolean 배열로 관리하기에 무리가 없다.
소스 코드
더보기
더보기
#include <stdio.h>
#include <stdlib.h>
int n, total, A[20];
bool isPossible[13 * 200010];
void func(int pos, int lsum, int rsum) {
if (pos == n) {
isPossible[abs(lsum - rsum)] = true;
return;
}
func(pos + 1, lsum, rsum);
func(pos + 1, lsum + A[pos], rsum);
func(pos + 1, lsum, rsum + A[pos]);
}
int main() {
scanf("%d", &n);
for (int i = 0 ; i < n ; ++i) {
scanf("%d", &A[i]);
total += A[i];
}
func(0, 0, 0);
int ans = 0;
for (int i = 1 ; i <= total ; ++i) {
if (!isPossible[i]) {
ans += 1;
}
}
printf("%d\n", ans);
}