문제
1653. 양팔 저울 : https://www.acmicpc.net/problem/1653
1653번: 양팔 저울
무게가 서로 다른 추들의 집합이 주어진다. 각 추의 무게는 1g 이상 9g 이하의 정수이다. 이 추들 중에서 몇 개를 선택하여 양팔저울에 올려서 평형을 만들고자 한다. 양팔저울에는 양쪽에 5개씩
www.acmicpc.net
문제 파악하기
- 추는 1g, 2g, ... , 9g까지 최대 9개가 있습니다.
- 양팔 저울에는 눈금이 5개씩 있으며, 평형을 이루게 만드는 추의 배치를 '평형정수'로 표현할 수 있으며, K번째 평형정수를 찾아야 합니다.
- 단순히 첫 번째 위치부터 추를 하나씩 놓으면 시간초과에 걸릴 수 있습니다.
- 어떤 방법으로 탐색을 해야 할까요?
문제 해결하기
- 추를 놓은 위치는 00001 ~ 98765 사이의 정수로 표현할 수 있습니다.
반대로 말하면 추는 항상 1 ~ 98765 사이의 정수로 표현됩니다. - 따라서 1 ~ 98765의 모든 정수에 대해, 계산되는 무게를 기준으로 정수를 나눠서 저장할 수 있습니다.
- 무게 별로 정수 2개를 한 쌍으로 묶어서 현재 가지고 있는 추로 표현할 수 있는 쌍인지 확인할 수 있습니다.
- 만약 현재 추로 만들 수 있는 한 쌍의 정수라면 서로 앞에 배치했을 때와 뒤에 배치했을 때의 평형 정수를 하나의 배열에 모아두면 됩니다.
- 모든 탐색이 끝나면 배열을 정렬한 후, K번째 평형 정수를 출력하면 됩니다.
소스 코드
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#include <stdio.h>
#include <vector>
#include <utility>
#include <algorithm>
#define NMAX 10
#define VMAX 120
#define PAIR pair<int,int>
using namespace std;
// 입력 변수
int n, k, t;
int inp[NMAX];
// 탐색 변수
vector< int > val[VMAX];
vector< long long int > v;
// 결과 변수
long long int ret;
bool chk(int k) {
int arr[NMAX]={0,};
while(k>0) {
arr[k%10]++;
k /= 10;
}
for(int i=1;i<NMAX;i++) {
if(arr[i] > inp[i]) return 0;
}
return 1;
}
int calc(int val) {
int ret=0;
for(int i=1;i<=5 and val>0;i++) {
ret += i*(val%10);
val /= 10;
}
return ret;
}
int convert(int val) {
int ret=0;
for(int i=1;i<=5;i++) {
ret = ret*10 + val%10;
val /= 10;
}
return ret;
}
bool isOk(int a, int b) {
int arr[NMAX]={0,};
while(a>0) {
arr[a%10]++;
a /= 10;
}
while(b>0) {
arr[b%10]++;
b /= 10;
}
for(int i=1;i<NMAX;i++) {
if(arr[i] > inp[i]) return 0;
}
return 1;
}
int main() {
// input
scanf("%d", &n);
for(int i=0;i<n;i++) {
scanf("%d", &t);
inp[t] = 1;
}
scanf("%d", &k);
for(int i=1;i<=98765;i++) {
if(!chk(i)) continue;
val[calc(i)].push_back(i);
}
for(int num=1;num<VMAX;num++) {
if(val[num].size() == 0) continue;
for(int i=0;i<val[num].size();i++) {
for(int j=i+1;j<val[num].size();j++) {
if(isOk(val[num][i], val[num][j])) {
v.push_back(val[num][i]*1LL*100000 + convert(val[num][j]));
v.push_back(val[num][j]*1LL*100000 + convert(val[num][i]));
}
}
}
}
v.push_back(0);
sort(v.begin(), v.end());
if(k>=v.size()) printf("%lld", v.back());
else printf("%lld", v[k]);
}
|
cs |
후기
나름 구현하기 복잡했던 문제라고 생각합니다. 추의 특성도 고려해야 시간초과에 걸리지 않기 때문에 나름 까다로운 문제이며, 브루트포스 알고리즘의 심화 문제로 추천하고 싶습니다.
'문제 노트 > 정올' 카테고리의 다른 글
나누기( BOJ 21757 ) (0) | 2021.10.21 |
---|---|
절사평균( BOJ 6986 ) (0) | 2021.09.27 |
배수( BOJ 2595 ) (0) | 2021.08.31 |
모빌 이진수( BOJ 2471 ) (0) | 2021.06.08 |
체인점( BOJ 2472 ) (0) | 2021.03.13 |