쩡류 2021. 11. 19. 13:18
728x90

https://acmicpc.net/problem/16236 

 

16236번: 아기 상어

N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다. 아기 상어와 물고기는 모두 크기를 가

www.acmicpc.net

 

- 1시간 10분이 걸린 문제.. 문제 조건을 꼼꼼하게 잘 읽고 풀었으면 10분은 단축시킬 수 있었을듯함

 

- BFS + 구현 문제이다. 시간복잡도는 의미없을 듯. BFS는 O(N^2)

 

- BFS를 진행하는 동안 해야 하는 것들을 살펴보면

 

  1) 물고기를 발견했을 때

 

    (1) 물고기가 상어보다 크다면 탐색 중단 

    (2) 크기가 같다면 queue에만 push. 지나갈 수는 있기 때문이다.

    (3) 작다면 먹을 수 있는 대상이다. 따로 vector에 해당 좌표를 push하고, 거리도 미리 저장을 해 둔다.

 

  2) 나보다 큰 물고기를 제외한 모든 구역들과 현재 상어의 구역과의 거리를 dist 배열에 저장한다.

 

- BFS를 마쳤을 때, 먹을 수 있는 물고기 후보군을 스캔하는데 만약 후보군이 없다면 엄마 상어를 호출해야 하므로 false를 return한다. 후보군이 있다면 최소 거리를 갖는 물고기를 한 번 더 필터링 해 준다. 그 후, 해당 벡터에 sort를 진행 할 건데 compare 커스텀 함수를 추가로 만들어 준다. 왜냐하면 x좌표, y좌표가 가장 작은 물고기를 먹어야 하기 때문이다. sort를 완료했다면 가장 맨 앞의 좌표를 선택해서, 해당 좌표의 물고기를 먹고 shark를 그 좌표로 이동시킨다. 추가로, shark의 크기를 늘릴 지를 체크 해 주고 true를 return한다.(물론 answer에도 이동거리를 추가 해 주어야 함.) 

 

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;

int dx[] = { 0,0,1,-1 };
int dy[] = { -1, 1,0,0 };
int arr[20][20];
int dist[20][20];
bool visited[20][20];
int n, answer;
int shark_x, shark_y,ate_fish, shark_size = 2;

bool compare(pair<int, int> a, pair<int, int> b) {
	if (a.first == b.first) return a.second < b.second;
	return a.first < b.first;
}

bool BFS(int start_x, int start_y) {
	int min_distance = 500;
	vector<pair<int, int>> possible_fish;
	queue<pair<pair<int, int>, int>> next_area;
	visited[shark_x][shark_y] = true;
	next_area.push({ {shark_x, shark_y}, 0 });
	while (!next_area.empty()) {
		int now_distance = next_area.front().second;
		int x = next_area.front().first.first;
		int y = next_area.front().first.second;
		next_area.pop();
		for (int i = 0; i < 4; i++) {
			int nx = x + dx[i];
			int ny = y + dy[i];
			if (nx < 0 || nx >= n || ny < 0 || ny >= n || visited[nx][ny]) continue;
			visited[nx][ny] = true;
			if (arr[nx][ny] != 0 && arr[nx][ny] != 9) { // 물고기인 경우
				if (arr[nx][ny] > shark_size) continue; // 물고기가 상어보다 큰 경우 pass
				else if (arr[nx][ny] == shark_size) { // 물고기가 상어와 같은 경우 지나갈 수 있게만 표시
					dist[nx][ny] = now_distance + 1;
					next_area.push({ { nx,ny }, now_distance + 1 });
					continue;
				}
				possible_fish.push_back({ nx,ny });
				min_distance = min(min_distance, now_distance + 1);
			}
			dist[nx][ny] = now_distance + 1;
			next_area.push({ {nx,ny}, now_distance + 1 });
		}
	}
	if (possible_fish.size() == 0) return false;
	vector<pair<int, int>> close_fish;
	for (int i = 0; i < possible_fish.size(); i++) {
		int x = possible_fish[i].first;
		int y = possible_fish[i].second;
		if (dist[x][y] == min_distance) close_fish.push_back({ x,y });
	}
	sort(close_fish.begin(), close_fish.end(), compare);
	arr[close_fish.front().first][close_fish.front().second] = 9;
	arr[shark_x][shark_y] = 0;
	shark_x = close_fish.front().first;
	shark_y = close_fish.front().second;
	answer += min_distance;
	ate_fish++;
	if (ate_fish == shark_size) {
		shark_size++;
		ate_fish = 0;
	}
	memset(dist, 0, sizeof(dist));
	memset(visited, false, sizeof(visited));
	
	return true;
}

int main() {
	cin >> n;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> arr[i][j];
			if (arr[i][j] == 9) {
				shark_x = i;
				shark_y = j;
			}
		}
	}
	while (BFS(shark_x, shark_y));
	cout << answer;
	return 0;
}