정화 코딩
[C++] Φ² (백준 30885번) 본문
https://www.acmicpc.net/problem/30885
#include <iostream>
#include <list>
using namespace std;
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
list<pair<long long, int>> li;
int n;
cin >> n;
for (int i = 1; i < n + 1; i++) {
int x;
cin >> x;
li.emplace_back(x, i);
}
while (li.size() > 1) {
for (auto i = li.begin(); i != li.end(); i++) {
long long a = i->first; // 현재 가리키고 있는 미생물의 크기
long long newa = a; // 새로운 미생물의 크기 (흡수 후)
// 첫 번째 미생물이 아닐 때만
if (i != li.begin()) {
auto prev_i = prev(i);
// 바로 앞 미생물이 작거나 같으면
if (prev_i->first <= a) {
newa += prev_i->first;
// i는 계속 현재 미생물을 가리키도록 유지
i = li.erase(prev_i);
}
}
// 마지막 미생물이 아닐 때만
if (next(i) != li.end()) {
auto next_i = next(i);
// 바로 뒤 미생물이 작거나 같으면
if (next_i->first <= a) {
newa += next_i->first;
// i는 계속 현재 미생물을 가리키도록 유지
i = li.erase(next_i);
i--;
}
}
// 미생물의 크기 갱신
i->first = newa;
}
}
auto ans = li.begin();
cout << ans->first << '\n' << ans->second << '\n';
}
우선 모든 미생물을 연결 리스트에 담는다. first에는 미생물의 크기를, second에는 미생물의 초기 위치를 넣었다.
그 후 미생물이 한 마리만 남을 때까지 다음을 반복한다.
1. 앞에 미생물이 존재할 경우, 바로 앞 미생물이 작거나 같으면 흡수한다. 이 때, 바로 앞 미생물의 바로 다음 미생물이 현재 미생물이므로 i는 erase에서 그대로 받는다.
2. 뒤에 미생물이 존재할 경우, 바로 뒤 미생물이 작거나 같으면 흡수한다. 이 때, 바로 뒤 미생물의 바로 다음 미생물은 현재 미생물 기준 바로 뒤 미생물이 되므로 i는 erase에서 받은 후 1을 빼준다.
3. 미생물의 크기를 흡수 후의 크기로 갱신해준다.
* erase 함수는 list에서 해당 iterator 위치의 원소를 삭제하고 원래 위치의 다음 원소의 iterator를 반환한다.
* prev 함수는 list에서 해당 iterator 위치의 원소의 바로 앞 원소의 iterator를 반환한다.
* next 함수는 list에서 해당 iterator 위치의 원소의 바로 뒤 원소의 iterator를 반환한다.
* prev, next 함수를 사용할 때는 범위가 벗어나 정의되지 않은 동작(Undefined Behavior)이 발생하지 않도록 주의해야 한다.
처음 풀어보는 연결 리스트 문제. C++에서 list를 아예 처음 써보는 것 같다.
그래서 좀 어려웠지만 C++ STL list에 대해서 이것 저것 배울 수 있어서 유익했다.
[참고] https://blog.naver.com/jinhan814/222508424732
'PS' 카테고리의 다른 글
[C++] 행렬 제곱 (백준 10830번) (0) | 2025.01.23 |
---|---|
[C++] 에디터 (백준 1406번) (2) | 2025.01.22 |
[C++] 버블버블 (백준 31870번) (0) | 2025.01.22 |
[C++] 악마 게임 (백준 16677번) (0) | 2025.01.22 |
[C++] D-Day (백준 1308번) (0) | 2025.01.08 |