16236 아기 상어

2020. 11. 22. 01:18·알고리즘/BOJ

www.acmicpc.net/problem/16236

 

16236번: 아기 상어

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

www.acmicpc.net

 

끔찍한 구현 문제였다. 어떻게 구현해야 할지 생각이 안 나서 다른 풀이를 참고했는데

pair 객체를 통해 정렬해주면 쉽게 풀리는데 잘 익혀둬야겠다.

 

  • 더 이상 먹을 수 있는 물고기가 공간에 없다면 아기 상어는 엄마 상어에게 도움을 요청한다.
  • 먹을 수 있는 물고기가 1마리라면, 그 물고기를 먹으러 간다.
  • 먹을 수 있는 물고기가 1마리보다 많다면, 거리가 가장 가까운 물고기를 먹으러 간다.
    • 거리는 아기 상어가 있는 칸에서 물고기가 있는 칸으로 이동할 때, 지나야 하는 칸의 개수의 최솟값이다.
    • 거리가 가까운 물고기가 많다면, 가장 위에 있는 물고기, 그러한 물고기가 여러마리라면, 가장 왼쪽에 있는 물고기를 먹는다.

 

문제에서 요구하는 조건을 잘 충족시켜줘야 하는데

일단 큰 틀을 짜보면 shark 구조체를 만들어두고 상어가 이동할 때마다 shark 구조체로 접근하면 된다.

 

  • 상어 구조체는 x, y, size(상어의 크기), eat(얼마나 먹었는지)로 설정해주고
  • 입력받을 때 상어가 있는 위치에서 shark = { i,j,2,0 }으로 입력받는다
  • 상어의 위치에서 BFS를 돌리는데 BFS를 통해 조건에 맞는 먹이가 있다면 feed 벡터에 push 해준다
  • 먹이가 없을 때까지 이동하는데 먹이가 없는 조건은
    • 아기 상어보다 더 작은 물고기가 없는 경우
    • map에 먹이가 없는 경우
  • 이외에 먹이가 있다면 feed 벡터를 정렬하고
  • 위치 값과 ans를 갱신해준다

 

이런 틀로 접근했다.

 

input 파트부터 보면

 

	cin >> n;
	for (int i=0;i<n;++i)
		for (int j = 0; j < n; ++j) {
			cin >> ar[i][j];
			if (ar[i][j] == 9) { //상어가 있는 자리라면
				ar[i][j] = 0; //0으로 만들어주고
				shark = { i,j,2,0 }; //상어의 위치를 넣어준다
			}   //상어는 i, j 에 있고 시작 크기는 2이다
		}

 

 

process 과정을 보면

 

	while (1) {
		bfs(shark.x, shark.y); //상어의 시작 위치에서 BFS

		if (feed.empty()) break; //조건에 맞는 먹이가 없다면 종료
		else {
			sort(feed.begin(), feed.end()); //정렬하고 갱신

			shark.x = feed[0].second.first;
			shark.y = feed[0].second.second;
			ans += feed[0].first;
			++shark.eat;

			ar[shark.x][shark.y] = 0; //맵 갱신
            //아기 상어가 먹은 먹이가 size와 같다면 size + 1
			if (shark.sz == shark.eat) shark.eat = 0, ++shark.sz;
		}
	}

 

이제 제일 중요한 BFS 부분인데 BFS를 통해서 조건에 맞는 먹이를 잘 구해줘야 한다.

 

void bfs(int x, int y) {
	fill(&d[0][0], &d[20][21], 0); //거리값은 BFS 돌릴 때마다 0으로 초기화
	queue<pair<int, int>> q;
	feed.clear(); //feed도 BFS할 때마다 초기화
	
	q.push({ x,y });

	while (!q.empty()) {
		auto cur = q.front(); q.pop();
		for (int i = 0; i < 4; ++i) {
			int nx = cur.first + dx[i];
			int ny = cur.second + dy[i];
			if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue; //범위 밖에 있다면 pass
            // 방문하지 않았고, 상어의 크기가 더 크다면
			if (d[nx][ny] == 0 && shark.sz >= ar[nx][ny]) {
				d[nx][ny] = d[cur.first][cur.second] + 1; //거리값 갱신하고 큐에 넣어준다
                q.push({ nx,ny });
                //맵에 먹이가 존재하고, 상어보다 작다면 
				if (ar[nx][ny] && shark.sz > ar[nx][ny])
                	//조건에 맞는 먹이니까 feed에 넣어준다
					feed.push_back({ d[nx][ny],{nx,ny} });
			}
		}
	}
}

 

중요한 점은 feed 벡터를 선언할 때, pair의 우선순위가 dist, x, y 순으로 와야 sort 할 때 우선순위가 

거리가 가장 작은 순, 가장 위쪽, 왼쪽 순을 맞출 수 있다.

아니라면 따로 람다 함수를 작성하던가 bool comp를 작성해서 맞춰줘야 한다.

 

전체 소스 코드

 

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

struct Shark { int x, y, sz, eat; };
int n, ans, ar[21][21], d[21][21];
vector<pair<int, pair<int, int>>> feed;
int dx[4] = { 0,1,0,-1 };
int dy[4] = { 1,0,-1,0 };
Shark shark;

void bfs(int x, int y) {
	fill(&d[0][0], &d[20][21], 0);
	queue<pair<int, int>> q;
	feed.clear();
	
	q.push({ x,y });

	while (!q.empty()) {
		auto cur = q.front(); q.pop();
		for (int i = 0; i < 4; ++i) {
			int nx = cur.first + dx[i];
			int ny = cur.second + dy[i];
			if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
			if (d[nx][ny] == 0 && shark.sz >= ar[nx][ny]) {
				d[nx][ny] = d[cur.first][cur.second] + 1;
				q.push({ nx,ny });

				if (ar[nx][ny] && shark.sz > ar[nx][ny])
					feed.push_back({ d[nx][ny],{nx,ny} });
			}
		}
	}
}

int main() {
	ios::sync_with_stdio(false); cin.tie(0);

	cin >> n;
	for (int i=0;i<n;++i)
		for (int j = 0; j < n; ++j) {
			cin >> ar[i][j];
			if (ar[i][j] == 9) {
				ar[i][j] = 0;
				shark = { i,j,2,0 };
			}
		}

	while (1) {
		bfs(shark.x, shark.y);

		if (feed.empty()) break;
		else {
			sort(feed.begin(), feed.end());

			shark.x = feed[0].second.first;
			shark.y = feed[0].second.second;
			ans += feed[0].first;
			++shark.eat;

			ar[shark.x][shark.y] = 0;
			if (shark.sz == shark.eat) shark.eat = 0, ++shark.sz;
		}
	}

	cout << ans << endl;

	return 0;
}

 

'알고리즘 > BOJ' 카테고리의 다른 글

BOJ 1005 ACM Craft  (0) 2020.11.25
BOJ 3055 탈출  (0) 2020.11.24
BOJ 11048 이동하기  (0) 2020.11.20
BOJ 인내의 도미노 장인 호석  (0) 2020.11.19
BOJ 4386 별자리 만들기  (0) 2020.11.14
'알고리즘/BOJ' 카테고리의 다른 글
  • BOJ 1005 ACM Craft
  • BOJ 3055 탈출
  • BOJ 11048 이동하기
  • BOJ 인내의 도미노 장인 호석
khyu2
khyu2
  • khyu2
    dev log
    khyu2
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 알고리즘
        • BOJ
        • Programmers
        • Algorithm
        • SWEA
      • 개발
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    이분 탐색
    코딩테스트 연습
    완전 탐색
    냅색
    완전탐색
    다익스트라
    시뮬레이션
    구현
    크루스칼
    피보나치 수
    분할 정복
    이분탐색
    행렬 제곱
    피사노 주기
    유니온 파인드
    SWEA
    GREEDY
    프로그래머스
    dp
    큐
    BFS
    조합
    트리
    팰린드롬
    소수
    MST
    BOJ
    우선순위 큐
    알고리즘
    dfs
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
khyu2
16236 아기 상어
상단으로

티스토리툴바