개인사
[G4] 백준 5913번 준규와 사과 C++ 백트래킹 본문
728x90

리뷰

https://www.acmicpc.net/problem/5913
좌측 상단과 우측 하단에서부터 시작해 맵의 모든 지점을 방문하고 마지막에 동일한 좌표에서 만나는 문제
전역 변수
- v : 방문 정보를 저장할 2차원 배열
- dx, dy : 4방향 탐색을 위한 방향 배열
- k : 방문 불가한 좌표의 개수를 저장할 변수
- ans : 모든 조건을 만족하는 좌표의 개수
함수
1. print
void print(const pii& j, const pii& h) {
cout << "\n";
for (int i = 0; i < 5; ++i) {
for (int k = 0; k < 5; ++k) {
if (j.first == h.first && j.second == h.second) cout << 'm';
else if (i == j.first && k == j.second) cout << 'j';
else if (i == h.first && k == h.second) cout << 'h';
else cout << v[i][k];
}
cout << "\n";
}
}
디버깅용 함수
2. bt
void bt(const pii& j, const pii& h, int remain) {
if (remain <= 0) {
if (j.first == h.first && j.second == h.second) ++ans;
return;
}
if (j.first == h.first && j.second == h.second) return;
//print(j, h);
int jx = j.first, jy = j.second;
int hx = h.first, hy = h.second;
for (int i = 0; i < 4; ++i) {
int njx = jx + dx[i], njy = jy + dy[i];
if (njx < 0 || njx > 4 || njy < 0 || njy > 4 || v[njx][njy]) continue;
for (int k = 0; k < 4; ++k) {
int nhx = hx + dx[k], nhy = hy + dy[k];
if (nhx < 0 || nhx > 4 || nhy < 0 || nhy > 4 || v[nhx][nhy]) continue;
v[njx][njy] = true;
v[nhx][nhy] = true;
bt({ njx, njy }, { nhx, nhy }, remain - 2);
v[njx][njy] = false;
v[nhx][nhy] = false;
}
}
}
백트래킹을 통해 맵을 방문하며 조건에 만족하는 모든 경우를 구하기 위한 함수
문제풀이
- 변수 apple을 25로 초기화한다.
- k값을 입력 받고, k개의 좌표를 입력 받아 v배열을 통해 해당 좌표를 방문처리 및 apple의 개수를 감소시킨다.
- 초기 좌표인 0, 0과 4, 4에 방문 처리를한다.
- bt함수에 {0, 0}, {4, 4}, apple-2를 매개변수로 전달하여 호출한다.
- bt함수는 변수 j, h, remain에 각각 준규의 좌표, 해빈이의 좌표, 남은 사과 개수를 저장한다.
- 기저 조건으로 remain이 0이하일 경우 j, h의 좌표가 같다면 ans를 증가한다. 이후 조건 여부와 상관없이 리턴한다.
- 두번쨰 기저 조건으로 j, h의 좌표가 같다면 리턴한다.
- 변수 jx, jy, hx, hy에 준규와 해빈이의 좌표를 파싱한다.
- 4방향 탐색을 수행하며 준규가 이동할 좌표가 범위 밖이거나 이미 방문했다면 continue처리한다.
- 4방향 탐색을 수행하며 해빈이가 이동할 좌표가 범위 밖이거나 이미 방문했다면 continue처리한다.
- 둘 모두 유효한 좌표일 경우에만 방문 처리 후 이동한 좌표와 remain-2를 매개변수로 전달하여 재귀를 수행한다.
- 재귀를 빠져나온 뒤엔 방문 처리한 내용을 원상 복구시켜준다.
- 모든 백트래킹을 마친 후 ans에 저장된 값을 출력한다.
트러블 슈팅
없음
참고 사항
- 0-based-indexing을 사용했으므로 k개의 좌표를 입력 받아 방문처리할때 좌표를 전위 감소 시켜주었다.
- 시작점인 (0,0)과 (4,4)에는 항상 사과 나무가 심어져 있다. 따라서 초기 백트래킹 시 방문처리 및 apple을 감소시켰다.
- 남은 사과가 없는데 j, h가 만난 경우만 ans를 증가, 아니라면 종료 처리하였다.
- 또, 마지막을 제외하고 같은 칸에서 만날 수는 없다라는 조건이 있으므로 사과가 남아있는데 j, h가 만난 경우는 더 이상 탐색할 필요가 없어 조기종료해주었다.
정답 코드
#include<iostream>
using namespace std;
using pii = pair<int, int>;
bool v[5][5];
int dx[] = { 1, -1, 0, 0 };
int dy[] = { 0, 0, 1, -1 };
int k, ans;
void print(const pii& j, const pii& h) {
cout << "\n";
for (int i = 0; i < 5; ++i) {
for (int k = 0; k < 5; ++k) {
if (j.first == h.first && j.second == h.second) cout << 'm';
else if (i == j.first && k == j.second) cout << 'j';
else if (i == h.first && k == h.second) cout << 'h';
else cout << v[i][k];
}
cout << "\n";
}
}
void bt(const pii& j, const pii& h, int remain) {
if (remain <= 0) {
if (j.first == h.first && j.second == h.second) ++ans;
return;
}
if (j.first == h.first && j.second == h.second) return;
//print(j, h);
int jx = j.first, jy = j.second;
int hx = h.first, hy = h.second;
for (int i = 0; i < 4; ++i) {
int njx = jx + dx[i], njy = jy + dy[i];
if (njx < 0 || njx > 4 || njy < 0 || njy > 4 || v[njx][njy]) continue;
for (int k = 0; k < 4; ++k) {
int nhx = hx + dx[k], nhy = hy + dy[k];
if (nhx < 0 || nhx > 4 || nhy < 0 || nhy > 4 || v[nhx][nhy]) continue;
v[njx][njy] = true;
v[nhx][nhy] = true;
bt({ njx, njy }, { nhx, nhy }, remain - 2);
v[njx][njy] = false;
v[nhx][nhy] = false;
}
}
}
int main() {
int apple = 25;
cin >> k;
while (k--) {
int x, y; cin >> x >> y;
v[--x][--y] = true;
--apple;
}
v[0][0] = true, v[4][4] = true;
bt({ 0, 0 }, { 4, 4 }, apple - 2);
cout << ans;
}728x90
'알고리즘 공부 > C++' 카테고리의 다른 글
| [G3] 백준 23326번 홍익 투어리스트 C++ 이분 탐색, 집합, set, lower_bound (0) | 2025.12.02 |
|---|---|
| [G4] 백준 10216번 Count Circle Groups C++ 너비 우선 탐색, 기하학, BFS (0) | 2025.12.01 |
| [G5] 백준 22862번 가장 긴 짝수 연속한 부분 수열 (large) C++ 투 포인터 (0) | 2025.11.27 |
| [G4] 백준 10159번 저울 C++ 플로이드 와샬 (0) | 2025.11.26 |
| [G5] 백준 5588번 별자리 찾기 C++ 브루트포스 알고리즘, 해시 집합, unordered_set (0) | 2025.11.25 |
