리뷰
https://www.acmicpc.net/problem/16920
각 라운드 마다 플레이어 번호가 낮은 순서부터 확장할 수 있을 만큼 확장 후 최종적으로 플레이어 마다 확장한 크기만큼을 출력하는 문제
전역 변수
- N : 맵 한변의 최대 길이를 정의할 상수 변수
- P : 플레이어 관련 배열의 최대 길이를 정의할 상수 변수
- n, m : 맵의 세로/가로 변의 길이를 저장할 변수
- p : 플레이어 수를 저장할 변수
- v : 맵의 방문 여부를 저장할 배열
- S : 플레이어 당 한 턴에 이동할 수 있는 거리를 저장할 배열
- cnt : 플레이어 당 점령한 성의 개수를 저장할 배열
- Pos : 시뮬레이션 시 사용할 현재 위치와 남은 이동 횟수를 정의할 구조체
- dx, dy : 4방향 탐색을 위한 방향 배열
- qs : 플레이어 별 Pos타입의 큐를 저장할 벡터
함수
1. solution
void solution() {
bool con = get_con();
while (con) {
for (int i = 1; i <= p; ++i) {
floodfill(i);
}
con = get_con();
}
for (int i = 1; i <= p; ++i) cout << cnt[i] << " ";
}
이동할 수 있을 때 까지 라운드를 진행하기 위한 함수
2. get_con
bool get_con() {
for (const auto& q : qs) {
if (!q.empty()) return true;
}
return false;
}
더 이상 이동할 수 있는지 여부를 체크하기 위한 함수
3. floodfill
void floodfill(int pn) {
queue<Pos> q;
swap(q, qs[pn]);
while (!q.empty()) {
Pos pos = q.front(); q.pop();
int cx = pos.cx, cy = pos.cy, rm = pos.rm;
for (int i = 0; i < 4; ++i) {
int nx = cx + dx[i], ny = cy + dy[i], nrm = rm - 1;
if (0 <= nx && nx < n && 0 <= ny && ny < m && !v[nx][ny]) {
v[nx][ny] = true;
cnt[pn]++;
if (nrm) q.push({ nx, ny, nrm });
else qs[pn].push({nx, ny, S[pn]});
}
}
}
}
너비 우선 탐색을 통해 확장을 구현하기 위한 함수
문제풀이
- n, m, p값을 입력 받고, 플레이어 번호가 1-based-indexing으로 주어지므로 qs벡터를 p+1크기로 초기화 한다.
- p명의 플레이어가 한 라운드에 이동할 수 있는 거리를 S배열에 입력 받아준다.(마찬가지로 1-based-indexing)
- n*m크기의 맵 정보를 입력 받고, 현재 위치가 벽이라면 v배열에 방문 처리를 진행해 준다.
- 플레이어 번호가 주어진 경우 방문처리 후 cnt를 증가, qs에 플레이어 번호의 큐에 좌표와 이동횟수를 push한다.
- solution함수를 호출하여 아무 플레이어도 더 이상 확장할 수 없을 때 까지 확장을 진행해 준다.
- 변수 con에 get_con함수를 호출한 결과값을 저장해 준다.
- get_con함수는 qs를 순회하며 모든 큐가 비어있다면 false를, 하나의 큐라도 비지 않았다면 true를 반환한다.
- con이 true일 경우를 조건으로 하는 while루프를 수행하고, 각 플레이어 번호를 순회해 준다.
- 플레이어의 큐가 빈 상태라면 continue를, 비지 않았다면 floodfill함수에 플레이어 번호를 전달하여 호출한다.
- floodfill함수는 플레이어 번호 pn을 매개변수로 전달 받는다.
- Pos타입의 큐 q를 초기화 하고, swap함수를 통해 q와 qs[pn]을 바꾸어 준다.
- q가 빌때까지 while루프를 수행하고, 매 루프마다 요소를 한개씩 꺼내어 준다.
- 변수 cx, cy, rm에 현재 요소의 위치와 남은 이동 횟수를 파싱하여 저장해 준다.
- 4방향 탐색을 진행하고 이동할 위치를 변수 nx, ny, 이동 후 남은 이동 횟수 nrm에 rm-1값을 저장해 준다.
- 맵의 범위 내에 있으면 방문하지 않은 지역이라면 이동 후 방문처리 및 cnt[pn]을 증가시킨다.
- nrm이 0이 아니라면 q에 이동 위치와 nrm을 push하고 0이라면 qs[pn]에 이동 위치와 S[pn]을 push한다.
- soultion함수의 while루프가 종료되면 1~p번의 플레이어 번호에 저장된 cnt값을 공백을 기준으로 출력한다.
트러블 슈팅
- 우선 순위 큐 2개를 활용하여 플레이어 번호가 낮은 순서대로 처리하도록 구현하였는데 12%에서 Fail을 받았다.
- 플레이어 별 큐를 구현하여 낮은 플레이어 순서대로 floodfill함수를 호출하는 형식으로 바꾸어 AC를 받았다.
참고 사항
- 플레이어 마다 큐를 구현하지 않고 우선순위 큐 2개로도 될 줄 알았는데 Fail을 받는 이유와 반례는 찾지 못했다.
- 입력으로 주어지는 플레이어 번호는 1-based-indexing이므로 for문을 돌릴 때 주의를 기울이자
정답 코드
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 1e3;
const int P = 10;
int n, m, p;
bool v[N][N];
int S[P];
int cnt[P];
struct Pos {
int cx, cy, rm;
};
int dx[] = { 1, -1, 0, 0 };
int dy[] = { 0, 0, 1, -1 };
vector<queue<Pos>> qs;
void floodfill(int pn) {
queue<Pos> q;
swap(q, qs[pn]);
while (!q.empty()) {
Pos pos = q.front(); q.pop();
int cx = pos.cx, cy = pos.cy, rm = pos.rm;
for (int i = 0; i < 4; ++i) {
int nx = cx + dx[i], ny = cy + dy[i], nrm = rm - 1;
if (0 <= nx && nx < n && 0 <= ny && ny < m && !v[nx][ny]) {
v[nx][ny] = true;
cnt[pn]++;
if (nrm) q.push({ nx, ny, nrm });
else qs[pn].push({nx, ny, S[pn]});
}
}
}
}
bool get_con() {
for (const auto& q : qs) {
if (!q.empty()) return true;
}
return false;
}
void solution() {
bool con = get_con();
while (con) {
for (int i = 1; i <= p; ++i) {
if (qs[i].empty()) continue;
floodfill(i);
}
con = get_con();
}
for (int i = 1; i <= p; ++i) cout << cnt[i] << " ";
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> p;
qs.resize(p + 1);
for (int i = 1; i <= p; ++i) cin >> S[i];
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
char ch; cin >> ch;
if (ch == '.') continue;
else if (ch == '#') v[i][j] = true;
else {
int num = ch - '0';
v[i][j] = true;
cnt[num]++;
qs[num].push({i, j, S[num]});
}
}
}
solution();
}
728x90
'알고리즘 공부 > C++' 카테고리의 다른 글
[G5] 백준 33905번 영일 마을에 살고 있는 엄은 친구의 집에 가고 싶다 C++ 너비 우선 탐색 (0) | 2025.06.01 |
---|---|
[G2] 백준 2637번 장난감 조립 C++ 위상 정렬, 다이나믹 프로그래밍 (0) | 2025.05.31 |
[G4] 백준 2479번 경로 찾기 C++ 너비 우선 탐색 (0) | 2025.05.28 |
[G5] 백준 16938번 캠프 준비 C++ 백트래킹, 정렬 (0) | 2025.05.27 |
[G5] 백준 15661번 링크와 스타트 C++ 백트래킹 (0) | 2025.05.26 |