본문 바로가기

알고리즘/SWEA

2382

typedef pair<int, int> pos;

static int N, M, K;
static int board[2][100][100];
static int direction[2][100][100];

static int tmp[100][100];
static queue<pos> q;

static int d[5][2] = {
	0, 0,
	-1, 0, //상, 실수했던 부분,
	1, 0, //하, //
	0, -1, //좌
	0, 1 //우
};

static int changed[5] = { 0, 2, 1, 4, 3 };

static int solution(void)
{
	int y, x, nr, dir;
	int turn = 0, ret = 0;

	scanf("%d %d %d", &N, &M, &K);
	for (int i = 0; i < K; i++)
	{
		scanf("%d %d %d %d", &y, &x, &nr, &dir);
		q.push({ y, x });
		board[turn][y][x] = nr;
		direction[turn][y][x] = dir;
	}

	for (int h = 0; h < M; h++)
	{
		int q_sz = q.size();

		for (int cnt = 0; cnt < q_sz; cnt++)
		{
			pos cur = q.front();
			q.pop();
			dir = direction[turn][cur.first][cur.second];

			int ny = cur.first + d[dir][0];
			int nx = cur.second + d[dir][1];

			if (ny == 0 || ny == N - 1 || nx == 0 || nx == N - 1) //약품으로 칠해진 셀,
			{
				board[turn][cur.first][cur.second] /= 2;
				direction[turn][cur.first][cur.second] = changed[dir];
			}

			if (!tmp[ny][nx]) //비어있었다면,
				q.push({ ny, nx });

			if (board[turn][cur.first][cur.second] > tmp[ny][nx]) //군집의 수가 더 큰 경우
			{
				tmp[ny][nx] = board[turn][cur.first][cur.second];
				direction[1 - turn][ny][nx] = direction[turn][cur.first][cur.second];
			}
			board[1 - turn][ny][nx] += board[turn][cur.first][cur.second]; //누적,
		}

		memset(board[turn], 0, sizeof(board[turn]));
		memset(direction[turn], 0, sizeof(direction[turn])); //오타가 있었던 부분,
		memset(tmp, 0, sizeof(tmp));
		turn = 1 - turn;
	}

	while (q.size())
	{
		pos cur = q.front();
		q.pop();
		ret += board[turn][cur.first][cur.second];
	}

	memset(board[turn], 0, sizeof(board[turn]));
	memset(direction[turn], 0, sizeof(direction[turn]));

	return ret;
}

먼저 좌표를 이동 시키는 부분에서 실수가 있었다.

상, 하 에서 착각을 해서 y좌표에 1더하는 것을 위로 올라가는 경우로 처리했었다.

실수하지 말아야할 부분이다.

 

이어서 문제 풀이에 대해 설명하자면 

board는 각 위치에서 군집의 수를 표현하고, direction은 군집의 이동방향을 표현한다.

시간이 흐르면서 이 정보는 변하기 때문에, 3차원 배열로 선언하여 처리하였다.

 

시간이 0 부터 M - 1 까지, 총 M시간이 흐르는 것을 모델링 하였다.

먼저 약품으로 칠해진 셀로 이동한 경우를 처리한다.

 위 그림에서 화살표 1, 2는 상단, 하단 전부 약품으로 칠해진 셀이고, 이 때 y 는 0, (4 - 1) 이다.

화살표 3, 4는 좌측, 우측 전부 약품으로 칠해진 셀을 나타낸다. 이 때 x 는 0, (4 - 1) 이다.

즉, 이동할 y 나 x가 이와 같은 경우라면 현재 군집의 미생물 수를 절반으로 낮추고, 그 방향을 바꾼다.

 

그 다음 tmp는 해당 좌표의 visit정보 겸, 미생물 수의 최대값 검출을 위해 쓰인다. 

여러 군집이 같은 좌표로 향하는 경우, 큐에 중복된 좌표를 푸쉬하지 않게 하기 위함과,

여러 군집 중 미생물 수가 가장 많은 군집의 이동 경로로 설정하기 위함이다.

 

그리고 다음 시간대에 사용할 해당 좌표에서의 미생물 수를 누적하여, 여러 군집이 합쳐진 것을 표현 할 수 있다.

 

그리고 오타가 있었던 부분에서는 

memset(direction[turn], 0, sizeof(direction))으로 작성했었다.

그래서 처음에는 원하는 흐름대로 잘 되었지만, 그 다음 시간대에서는 이동할 방향의 인덱스가 0 이어서 미생물 군집이 이동하지 않아서 답이 틀리는 문제가 있었다.

사소한 실수 였는데, 이를 늦게 발견했다면 엉뚱한 곳에서 시간을 낭비하고 있을 뻔 했다.

주의해야 할 부분이다.

 

//

원래 생각은 priority_queue를 이용한 것이다.

priority_queue pqs[100][100];

이렇게 만들어서, 각 좌표에서 큐에 2개 이상의 군집이 있다면, 이 중 top 군집의 방향을 따라가는 식으로 하는 것이었다. 

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

8557  (0) 2021.11.08
8556  (0) 2021.11.08
8501  (0) 2021.11.08
2383  (0) 2021.11.04
8458  (0) 2021.11.04