문제 링크: https://www.acmicpc.net/problem/19236
올해 상반기 코테 기출이라고 합니다. 이런 문제는 읽기도 싫게 생겼습니다 끙;
그냥 적당히 써있는대로 풀면 됩니다. 45도씩 반시계로 회전하는건 적당히 d=(d+1)%8 이런식으로 하심 됩니다.
문제가 상어가 여러군데로 갈 수 있는 경우인데, 재귀함수로 백트래킹하거나, 상태공간 struct랑 큐를 만들어서 BFS를 돌려줘야 합니다. 어느 루트를 타야 먹은 애들의 합이 최대가 될 지 모르니까요. 결국은 모든 경우의 수를 다 해봐야 합니다.
8퀸 문제같은 경우 상태공간을 압축을 해줘야되는데(2차원 체스판 --> 1차원배열 --> 비트마스킹으로 8bit integer에 저장 등) 이 문제는 뭐 그럴 필요가 없습니다.
#include <bits/stdc++.h>
using namespace std;
// 윗쪽 방향부터 반시계로 45도씩
const int dy[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
const int dx[] = { 0, -1, -1, -1, 0, 1, 1, 1 };
// 이게 d=(d+1)%8보다 더 빠름
constexpr int turn(int d) {
return (d == 7 ? 0 : d + 1);
}
constexpr bool in_range(int y, int x) {
return y >= 0 && y < 4 && x >= 0 && x < 4;
}
struct status {
tuple<int, int, int> shark; // y, x, dir
pair<int, int> fish[4][4]; // index[1, 16], direction[0, 7], idx==0 -> 빈칸
int remain; // 남은 물고기
int eaten; // 먹은 물고기 번호 합
// 상어를 [y][x]로 이동
// ([y][x]에 물고기 있다고 가정)
void move_shark(int _y, int _x) {
auto& [y, x, d] = shark;
auto& [f_idx, f_dir] = fish[_y][_x];
assert(f_idx != 0);
y = _y, x = _x;
d = f_dir;
--remain;
eaten += f_idx;
f_idx = 0;
}
// 모든 물고기 이동
void move_fish() {
for (int idx = 1; idx <= 16; ++idx) {
bool found = false;
const auto& [s_y, s_x, s_dir] = shark;
for (int i = 0; i < 4 && !found; ++i) {
for (int j = 0; j < 4 && !found; ++j) {
auto& [f_idx, f_dir] = fish[i][j];
if (f_idx != idx) continue;
// 45도씩 돌려보기
for (int cnt = 0; cnt < 8; ++cnt) {
auto next_y = i + dy[f_dir];
auto next_x = j + dx[f_dir];
if (!in_range(next_y, next_x) || (s_y == next_y && s_x == next_x)) {
f_dir = turn(f_dir);
continue;
}
swap(fish[i][j], fish[next_y][next_x]);
found = true;
break;
}
}
}
} // for idx
}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
status input;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
int idx, dir;
cin >> idx >> dir;
--dir;
input.fish[i][j] = { idx, dir };
}
}
input.remain = 16;
input.eaten = 0;
// [0, 0] 물고기 먹기
input.move_shark(0, 0);
int mx = input.eaten;
queue<status> q;
q.push(input);
while (!q.empty()) {
auto current = q.front();
q.pop();
mx = max(mx, current.eaten);
current.move_fish();
auto [y, x, d] = current.shark;
auto next_y = y + dy[d];
auto next_x = x + dx[d];
while (in_range(next_y, next_x)) {
if (current.fish[next_y][next_x].first == 0) {
next_y += dy[d];
next_x += dx[d];
continue;
}
auto next_status = current;
next_status.move_shark(next_y, next_x);
if (next_status.remain)
q.push(next_status);
next_y += dy[d];
next_x += dx[d];
}
}
cout << mx << '\n';
return 0;
}
참고로 d=(d+1)%8보다 if else가 더 빠릅니다
근데 이 문제는 뭐 무한루프만 안나오면 어떻게 풀든 시간초과 날 일은 없습니다.
반응형
'Online Judge > 백준' 카테고리의 다른 글
[백준][C++] 1931: 회의실배정 (0) | 2020.07.12 |
---|---|
[백준][C++] 5430: AC (0) | 2020.07.11 |
[백준][C++] 1780: 종이의 개수 (0) | 2020.07.11 |
[백준][C++] 1764: 듣보잡 (0) | 2020.07.10 |
[백준][C++] 2993: 세 부분 (0) | 2020.07.09 |