티스토리 뷰

Algorithm/BOJ

[백준 17143] 낚시왕

giiro 2020. 8. 16. 01:11

 

문제

https://www.acmicpc.net/problem/17143

 

17143번: 낚시왕

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다.

www.acmicpc.net

 

문제 풀이

단순하게 시간복잡도를 생각해본다면 O(CMs) = O(109)로 TLE가 남

따라서 상어의 움직임을 줄여야 했고 아래의 관찰을 통해 해결함

  • (상어 H가 같은 위치로 돌아오는데 걸리는 시간) = (오른쪽으로 갔다가 돌아오는 시간) + (왼쪽으로 갔다가 돌아오는 시간)  

  • 이는 좌표를 우측 90도 방향으로 돌렸을때, (위,아래)로 움직이는 상어들도 동일하게 적용됨

  • 따라서 같은 위치로 돌아오는 주기  T=2(R1),T=2(C1) (∵ 양 끝 점은 한 번씩만 방문)   

if (di <= 2) v %= (2 * (R - 1)); // (dir <= 2) : left, right
else v %= (2 * (C - 1)); // (dir >= 3) : up, down

 

코드

더보기
#include <bits/stdc++.h>
using namespace std;
const int dir[5][2] = { { 0,0 },{ -1,0 },{ 1,0 },{ 0,1 },{ 0,-1 } };
struct shark {
int s, d, z;
};
int R, C, M, a, b, c, d, e, grid[101][101], tmp[101][101], ans;
shark f[10001];
void moveNeat() {
memset(tmp, 0, sizeof(tmp));
int v, sz, di, nr, nc;
for (int i = 1; i <= R; i++) {
for (int j = 1; j <= C; j++) {
if (grid[i][j]) {
v = f[grid[i][j]].s, di = f[grid[i][j]].d, sz = f[grid[i][j]].z;
nr = i, nc = j;
if (di <= 2) v %= (2 * (R - 1));
else v %= (2 * (C - 1));
while (v--) {
if ((nr == 1 && di == 1) || (nr == R && di == 2)) di = 3 - di;
else if ((nc == 1 && di == 4) || (nc == C && di == 3)) di = 7 - di;
nr += dir[di][0], nc += dir[di][1];
}
f[grid[i][j]].d = di;
if (!tmp[nr][nc]) tmp[nr][nc] = grid[i][j];
else if (f[tmp[nr][nc]].z < f[grid[i][j]].z) tmp[nr][nc] = grid[i][j];
}
}
}
for (int i = 1; i <= R; i++)
for (int j = 1; j <= C; j++)
grid[i][j] = tmp[i][j];
}
void fishing(int pos) {
for (int i = 1; i <= R; i++) {
if (grid[i][pos]) {
ans += f[grid[i][pos]].z;
grid[i][pos] = 0;
break;
}
}
}
int main() {
cin.tie(NULL); cout.tie(NULL);
ios_base::sync_with_stdio(false);
cin >> R >> C >> M;
for (int i = 1; i <= M; i++) {
cin >> a >> b >> c >> d >> e;
f[i] = { c,d,e };
grid[a][b] = i;
}
for (int t = 1; t <= C; t++) {
fishing(t);
moveNeat();
}
cout << ans;
}

 

어떻게 구현 ?

 

위의 생각까지 마쳤다면 두 함수를 구현할 수 있음

 

1. 상어를 잡는 함수

void fishing(int pos) {
for (int i = 1; i <= R; i++) {
if (grid[i][pos]) {
ans += f[grid[i][pos]].z;
grid[i][pos] = 0;
break;
}
}
}

 

2. 상어의 움직임을 제어하는 함수

 

memset(tmp, 0, sizeof(tmp));

 ⑴ 이동할 좌표에 상어정보 초기화

 

if ((nr == 1 && di == 1) || (nr == R && di == 2)) di = 3 - di;
else if ((nc == 1 && di == 4) || (nc == C && di == 3)) di = 7 - di;

 ⑵ 격자판의 끝 점에서 상어의 방향이 격자판 바깥을 향한다면 반대방향으로 돌려줌 

 

f[grid[i][j]].d = di; 

 ⑶ 이동이 끝난 후 해당 상어의 방향을 교체해줌

 

/* tmp[nr][nc] : 이동할 좌표의 상어인덱스
f[grid[i][j]] : 이동전 좌표의 상어인덱스*/
if (!tmp[nr][nc]) tmp[nr][nc] = grid[i][j];
else if (f[tmp[nr][nc]].z < f[grid[i][j]].z) tmp[nr][nc] = grid[i][j];

 ⑷ 이동한 좌표에 상어가 없다면 상어의 인덱스를 저장하고, 상어가 존재한다면 크기를 비교하여 크기가 더 큰 상어의 인덱스를 저장

 

 

for (int i = 1; i <= R; i++)
for (int j = 1; j <= C; j++)
grid[i][j] = tmp[i][j];

 ⑸ 이동한 좌표의 상어정보를 현 좌표에 갱신

 

 

'Algorithm > BOJ' 카테고리의 다른 글

[백준 19576] 약수  (0) 2020.08.31
[백준 19588] 상품권 준비  (0) 2020.08.31
[백준 19591] 독특한 계산기  (0) 2020.08.31
[백준 1662] 압축  (0) 2020.08.31
[백준 17080] 결함게임  (0) 2020.08.27
댓글