191009 백준 알고리즘 문제풀기

|

[16236] 아기 상어

  • 난이도: 상
  • 문제 풀이 떠올리는데 30분, 구현까지 해서 2시간 넘게 걸림.
  • 너무 조건이 많아 어렵다
  • 어이없는것은 분명 반례까지 다 맞았는데 자꾸 틀렸다고 채점된다. 이유를 모르겠다.

  • 문제
    • https://www.acmicpc.net/problem/16236
    • NxN 크기 맵이 주어지고, 아기 상어와 물고기들이 주어진다.
      • 물고기와 상어는 각 1칸씩 차지한다.
    • 처음 아기 상어 크기는 2이고, 1초마다 상하좌우 1칸씩 움직일 수 있다.
      • 자신과 크기가 같거나 작은 고기는 지나갈 수 있고, 크기가 작은 물고기만 먹을 수 있다.
      • 자신 크기의 개수만큼 물고기를 먹으면 크기가 1 증가한다.
    • 아기 상어 이동 결정은 다음과 같다.
      • 더 이상 먹을 수 있는 물고기가 공간에 없으면 엄마 상어에게 도움을 요청한다.
      • 먹을 수 있는 물고기가 1마리라면, 그 물고기를 먹으러 간다.
      • 먹을 수 있는 물고기가 1마리보다 많으면 거리가 가장 가까운 고기를 먹는다.
        • 아기상어는 항상 가까운 길로만 다닌다.
        • 가까운 물고기가 많다면 가장 위에 있는 물고기, 그중에서도 가장 왼쪽에 있는 물고기를 먹는다.
    • 이동은 어느칸이건 무조건 1초가 걸리고, 물고기를 먹는데 걸리는 시간은 없다.
      • 물고기는 이동과 동시에 먹는다.
    • 공간 상태가 주어졌을 때 아기 상어가 몇 초 동안 엄마 상어에게 도움 요청없이 물고기 먹을 수 있는지를 계산한다.
  • 풀이
    • 문제를 나누면
      • 물고기 상태 맵을 입력 받는다.
        • 입력 시엔 상어 위치만 저장하고 해당 위치를 0으로 초기화해서 지나갈 수 있는 상태로 만든다.
      • 상어가 갈 수 있는데를 찾고
      • 물고기를 먹고
      • 먹은 상태에 따라 상어 크기를 키운다.
        • 만약 먹을 수 있는 고기가 없었다면 끝낸다.
#pragma warning(disable:4996)
#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;

struct shark {
	int x, y, size;
};

int map[22][22];
int check[22][22];

int dx[] = { 0,-1,1,0 };
int dy[] = { -1,0,0,1 };

void init_check(int n)
{
	for (int j = 0; j < n; j++)
	{
		for (int i = 0; i < n; i++)
		{
			check[j][i] = 0;
		}
	}
}

void shark_grow(int &eat_cnt, shark &baby)
{
	if (eat_cnt == baby.size)
	{//만약 먹은량이 상어크기와 같다면
		baby.size++; // 상어 크기 키우고
		eat_cnt = 0; // 먹은량 초기화
	}
}

int main()
{
	int N;
	scanf("%d ", &N);
	shark baby;
	for (int j = 0; j < N; j++)
	{
		for (int i = 0; i < N; i++)
		{
			scanf("%d", &map[j][i]);
			if (map[j][i] == 9)
			{
				baby.x = i;
				baby.y = j;
				baby.size = 2;
				map[j][i] = 0;
			}
		}
	}

	int answer = 0;
	bool flag = false;
	int eat_count = 0;
	int timer = 0;
	while (1)
	{
		//더 이상 먹을 고기 없는 경우 빠져나간다.
		if (flag) break;

		//check 맵 매 초마다 초기화
		init_check(N);

		//상어 현재 위치 check
		queue<pair<int, int>> q;

		int cx = baby.x;
		int cy = baby.y;
		
		check[cy][cx] = 1;
		q.push(make_pair(cx, cy));
		bool eat = false;
		
		int distance = 1000;
		int min_x = 1000;
		int min_y = 1000;

		while (!q.empty())
		{
			cx = q.front().first;
			cy = q.front().second;
			q.pop();
			for (int i = 0; i < 4; i++)
			{ //상어 다음 위치를 간다.
				int nx = cx + dx[i];
				int ny = cy + dy[i];
				if (0 <= nx && nx < N && 0 <= ny && ny < N&&check[ny][nx] == 0 && map[ny][nx] <= baby.size)
				{//맵 영역 안이고, 간 적이 없고, 맵 물고기 크기가 상어 이하라면 간다.
					//일단 방문한다.
					check[ny][nx] = check[cy][cx] + 1;
					q.push(make_pair(nx, ny));
					if (0 < map[ny][nx] && map[ny][nx] < baby.size)
					{//먹을 수 있는 물고기가 존재한다면
						eat = true; // 먹는다고 표시 하고
						if (check[ny][nx] < distance)
						{//만약 지금 방문한 위치가 가장 가깝다면
							min_x = nx; // 최소 위치 초기화
							min_y = ny;
							distance = check[ny][nx];
						}
						else if (check[ny][nx] == distance)
						{//만약 지금 방문한 거리가 가장 가까운 거리와 같다면
							int temp = min_x;
							if (ny < min_y)
							{ // 가장 위의 물고기를 먹고
								min_x = nx;
								min_y = ny;
								if (nx < temp)
								{ // 그중에서도 왼쪽 물고길 먹는다.
									min_x = nx;
									min_y = ny;
								}
							}
						}
					}					
				}
			}
		}
		if (eat)
		{//먹은 고기가 있다면
			eat_count++; // 먹는다.
			baby.x = min_x; // 상어 위치 초기화
			baby.y = min_y;
			map[min_y][min_x] = 0; //먹힌 물고기 지우기
			timer += check[min_y][min_x] - 1; // 먹는데 걸린 시간 더하기

			//상어를 조건에 맞게 키운다.
			shark_grow(eat_count, baby);
		}
		else flag = true; //맵에 먹을 고기 없으면 끝낸다.
	}
	printf("%d\n", timer);
  
	//std::system("pause");
	return 0;
}