ps
[백준] 19236 - 청소년 상어
kariskan
2022. 8. 22. 22:25
https://www.acmicpc.net/problem/19236
19236번: 청소년 상어
첫째 줄부터 4개의 줄에 각 칸의 들어있는 물고기의 정보가 1번 행부터 순서대로 주어진다. 물고기의 정보는 두 정수 ai, bi로 이루어져 있고, ai는 물고기의 번호, bi는 방향을 의미한다. 방향 bi는
www.acmicpc.net
정말 이런 빡 구현 문제를 풀 때마다 수명이 줄어지는 것이 느껴진다.
이런 문제는 디버깅도 매우 어렵고 조금만 실수해도 답이 확 틀어진다.
이 문제를 다시 돌이켜보면, 그렇게 큰 실수가 아니었음에도 다시 풀면 한 번에 맞출 자신이 없다.
꾸준히 구현 문제를 풀어서 실수를 줄여나가야겠다.
먼저 물고기의 상태를 나타내는 구조체를 하나 선언하였다.
좌표, 방향, 생존여부이다.
struct fish {
int x;
int y;
int dir;
bool on;
};
그리고 나는 배열을 복사하는 코드를 적기 싫어해서 벡터로 선언해 참조 형태로 전달하였다.
다음은 물고기가 움직이는 과정이다.
- 1번 물고기부터, 16번 물고기까지 살아있을 때 진행한다.
- 해당 물고기의 방향을 포함해 반시계 방향으로 돌아가며 가능한 경우를 찾는다.
- 가능한 경우를 찾으면, 물고기를 스위칭해주고 break를 건다.
void fishMove(vector<fish>& f, vector<vector<int>>& map, pair<int, int> s) {
for (int i = 1; i <= 16; i++) {
if (!f[i].on) continue;
for (int k = 0; k < 8; k++) {
int nDir = f[i].dir + k;
if (nDir > 8) nDir -= 8;
int nx = f[i].x + dx[nDir];
int ny = f[i].y + dy[nDir];
if (nx >= 0 && nx < 4 && ny >= 0 && ny < 4 && !(nx == s.first && ny == s.second)) {
f[i].dir = nDir;
int nowDir = f[i].dir;
int nowX = f[i].x;
int nowY = f[i].y;
pair<int, int> coor = { f[i].x,f[i].y };
f[i].x = nx, f[i].y = ny;
f[map[nx][ny]].x = coor.first, f[map[nx][ny]].y = coor.second;
int num = map[nx][ny];
map[nx][ny] = i;
map[coor.first][coor.second] = num;
break;
}
}
}
}
다음은 dfs 과정이다.
물고기를 움직이고 나서, 상어는 해당하는 줄(행, 열, 대각선)에 최대 3마리의 물고기 중에서 하나를 고를 수 있다.
이 과정을 백트래킹으로 해결하였다.
void go(vector<fish> f, pair<int, int> s, int sDir, vector<vector<int>> map, int cnt) { //cnt = 먹은 물고기 개수
ans = max(ans, cnt);
fishMove(f, map, s);
//sharkMove start
for (int i = 1; i <= 3; i++) {
int nx = s.first + dx[sDir] * i;
int ny = s.second + dy[sDir] * i;
if (nx >= 0 && nx < 4 && ny >= 0 && ny < 4 && map[nx][ny]) {
int fishNum = map[nx][ny];
map[nx][ny] = 0;
f[fishNum].on = false;
go(f, { nx,ny }, f[fishNum].dir, map, cnt + fishNum);
map[nx][ny] = fishNum;
f[fishNum].on = true;
}
}
//sharkMove end
}
다음은 전체 코드이다.
#include <iostream>
#include <vector>
using namespace std;
int dx[9] = { 0,-1,-1,0,1,1,1,0,-1 };
int dy[9] = { 0,0,-1,-1,-1,0,1,1,1 };
int ans = 0;
struct fish {
int x;
int y;
int dir;
bool on;
};
void fishMove(vector<fish>& f, vector<vector<int>>& map, pair<int, int> s) {
for (int i = 1; i <= 16; i++) {
if (!f[i].on) continue;
for (int k = 0; k < 8; k++) {
int nDir = f[i].dir + k;
if (nDir > 8) nDir -= 8;
int nx = f[i].x + dx[nDir];
int ny = f[i].y + dy[nDir];
if (nx >= 0 && nx < 4 && ny >= 0 && ny < 4 && !(nx == s.first && ny == s.second)) {
f[i].dir = nDir;
int nowDir = f[i].dir;
int nowX = f[i].x;
int nowY = f[i].y;
pair<int, int> coor = { f[i].x,f[i].y };
f[i].x = nx, f[i].y = ny;
f[map[nx][ny]].x = coor.first, f[map[nx][ny]].y = coor.second;
int num = map[nx][ny];
map[nx][ny] = i;
map[coor.first][coor.second] = num;
break;
}
}
}
}
void go(vector<fish> f, pair<int, int> s, int sDir, vector<vector<int>> map, int cnt) { //cnt = 먹은 물고기 개수
ans = max(ans, cnt);
fishMove(f, map, s);
//sharkMove start
for (int i = 1; i <= 3; i++) {
int nx = s.first + dx[sDir] * i;
int ny = s.second + dy[sDir] * i;
if (nx >= 0 && nx < 4 && ny >= 0 && ny < 4 && map[nx][ny]) {
int fishNum = map[nx][ny];
map[nx][ny] = 0;
f[fishNum].on = false;
go(f, { nx,ny }, f[fishNum].dir, map, cnt + fishNum);
map[nx][ny] = fishNum;
f[fishNum].on = true;
}
}
//sharkMove end
}
int main() {
vector<fish> f(17);
vector<vector<int>> map(4, vector<int>(4));
pair<int, int> s = {};
int sDir = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
int num, dir;
cin >> num >> dir;
fish a = { i,j,dir,true };
f[num] = a;
map[i][j] = num;
}
}
int fNum = map[0][0];
s = { 0,0 }, sDir = f[fNum].dir;
f[fNum].on = false;
map[0][0] = 0;
go(f, s, sDir, map, fNum);
cout << ans;
}
생각보다 그리 코드가 길지 않은데 실수가 잦은 문제였다.