알고리즘/문제 풀이
2785번: 체인
Themion
2021. 12. 17. 17:18
https://www.acmicpc.net/problem/2785
2785번: 체인
희원이는 그의 다락방에서 N개의 체인을 찾았다. 각각의 체인은 몇 개의 고리로 연결되어 있는데, 각각의 고리는 최대 두 개의 인접한 고리를 가질 수 있다. 각각의 고리는 열고 닫을 수 있다. 그
www.acmicpc.net
체인이 k개이고 연 고리의 수가 k - 1개라면 모든 체인을 연 고리를 이용해 하나로 묶을 수 있다. 즉 열고 닫아야 할 최소한의 고리 수는 체인의 개수에 큰 영향을 받고, 체인의 개수가 줄면 줄 수록 열고 닫아야 할 고리의 수 역시 줄어든다.
체인을 체인이 가진 고리의 수에 대해 오름차순으로 정렬했다고 가정하자. 현재 가진 고리와 현재 체인의 고리를 모두 열어 얻은 고리의 합이 남은 체인보다 적다면, 우선 현재 체인을 모두 연 다음 다음 체인을 가져온다. 이렇게 해서 남은 체인을 모두 연결할 수 있는 경우가 발생한다면, 이 때 필요한 고리의 수의 최솟값은 총 체인의 개수 - 1개이므로, 이 개수를 만족할 때까지 체인의 고리를 열면 된다.
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int, vector<int>, greater<int>> q;
// q에서 원소를 하나 가져온 뒤 pop
int get() {
int ret = q.top();
q.pop();
return ret;
}
int main() {
// 입출력 속도 향상
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
// N: 체인의 개수, len: 체인의 길이, ans: 열고 닫아야 할 최소한의 고리의 수
int N, len, ans = 0;
// 체인의 개수를 입력받은 뒤
cin >> N;
for (int i = 0; i < N; i++) {
// 각 체인의 길이를 입력받아 우선순위 큐에 push
cin >> len;
q.push(len);
}
// 열고 닫을 고리를 가져올 체인을 우선순위 큐에서 가져온 뒤
len = get();
// 조건을 만족할 때까지
while (ans < q.size()) {
// 현재 체인을 모두 열어도 남은 모든 체인을 연결하지 못한다면
if (ans + len < q.size()) {
// 우선 남은 체인을 모두 연 뒤 다음 체인과 비교
ans += len;
len = get();
}
// 현재 체인으로 모든 체인을 연결할 수 있다면
// 고리는 총 (체인의 실제 개수 - 1)개가 필요하다
else ans = q.size();
}
// 열고 닫아야할 최소한의 고리 수를 출력
cout << ans << '\n';
return 0;
}