개인사
[P5] 백준 3895번 그리고 하나가 남았다 C++ 세그먼트 트리 본문
728x90

리뷰

https://www.acmicpc.net/problem/3895
요세푸스 문제와 유사한 문제
전역 변수
- N : 배열의 최대 크기를 정의할 상수 변수
- n : 돌의 개수를 저장할 변수
- k : 건너 뛸 돌의 개수를 저장할 변수
- m : 초기 돌의 번호를 저장할 변수
- tree : 세그먼트 트리 정보를 저장할 배열
함수
1. build
void build(int node, int s, int e) {
if (s == e) tree[node] = 1;
else {
int mid = (s + e) / 2;
build(node * 2, s, mid);
build(node * 2 + 1, mid + 1, e);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
}
세그먼트 트리 초기화를 위한 변수
2. query
int query(int node, int s, int e, int k) {
if (s == e) {
tree[node] = 0;
return s;
}
int mid = (s + e) / 2;
int result = k <= tree[node * 2] ? query(node * 2, s, mid, k) : query(node * 2 + 1, mid + 1, e, k - tree[node * 2]);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
return result;
}
도달한 돌을 제거하고, 세그먼트 트리의 업데이트 및 해당 돌의 번호를 리턴하기 위한 함수
문제풀이
- n, k, m값을 입력 받고, 모든 값이 0일 경우 break처리한다.
- build함수를 통해 리프 노드가 1인 상태로 누적합 세그먼트 트리 초기화를 진행한다.
- 변수 idx을 m, res를 임의의 값으로 출력한다.
- n번의 for문을 개행하고, 매 루프마다 query함수를 호출하여 idx번째 돌을 제거 후 돌의 번호를 res에 저장한다.
- 기저 조건으로 i가 n에 도달한 경우 마지막 돌이 남은 상태이므로 break처리한다.
- idx를 idx-1+k를 루트 노드의 값으로 나눈 나머지로 저장한다.
- 만약 idx가 0인경우 idx를 루트 노드의 값으로 저장한다.
- res에 저장된 값을 출력 후 개행문자를 삽입한다.
- 위 로직을 테스트케이스가 종료될 때 까지 반복한다.
트러블 슈팅
없음
참고 사항
- idx-1+k를 세그먼트 트리의 총 합으로 모듈러연산을 하면서 자동으로 다음 돌의 위치를 알 수 있다.
- 하지만 1-based-indexing인 상태에선 idx가 0인 경우를 분기처리해야한다.
- 마지막 돌이 남은 경우엔 break처리를 해주어야 무한루프를 방지할 수 있다.
정답 코드
#include<iostream>
using namespace std;
const int N = 1e4 + 1;
int n, k, m;
int tree[N * 4];
void build(int node, int s, int e) {
if (s == e) tree[node] = 1;
else {
int mid = (s + e) / 2;
build(node * 2, s, mid);
build(node * 2 + 1, mid + 1, e);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
}
int query(int node, int s, int e, int k) {
if (s == e) {
tree[node] = 0;
return s;
}
int mid = (s + e) / 2;
int result = k <= tree[node * 2] ? query(node * 2, s, mid, k) : query(node * 2 + 1, mid + 1, e, k - tree[node * 2]);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
return result;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while (1) {
cin >> n >> k >> m;
if (!n && !k && !m) break;
build(1, 1, n);
int idx = m, res = -1;
for (int i = 1; i <= n; ++i) {
res = query(1, 1, n, idx);
if (i == n) break;
idx = (idx - 1 + k) % tree[1];
if (idx == 0) idx = tree[1];
}
cout << res << "\n";
}
}728x90
'알고리즘 공부 > C++' 카테고리의 다른 글
| [G3] 백준 17951번 흩날리는 시험지 속에서 내 평점이 느껴진거야 C++ 이분 탐색, 매개 변수 탐색 (0) | 2025.11.06 |
|---|---|
| [G4] 백준 16469번 소년 점프 C++ 너비 우선 탐색, 플러드 필 (0) | 2025.11.04 |
| [G5] 백준 13164번 행복 유치원 C++ 그리디 알고리즘, 우선순위 큐 (0) | 2025.11.02 |
| [G5] 백준 11509번 풍선 맞추기 C++ 그리디 알고리즘 (0) | 2025.11.01 |
| [G5] 백준 20208번 진우의 민트초코우유 C++ 백트래킹 (0) | 2025.10.31 |
