🙇‍♀️[Gold IV] 마법사 상어와 파이어볼 - 20056

문제 링크

성능 요약

메모리: 3008 KB, 시간: 44 ms

분류

구현, 시뮬레이션

제출 일자

2024년 3월 17일 17:48:31

문제 설명

어른 상어가 마법사가 되었고, 파이어볼을 배웠다.

마법사 상어가 크기가 N×N인 격자에 파이어볼 M개를 발사했다. 가장 처음에 파이어볼은 각자 위치에서 이동을 대기하고 있다. i번 파이어볼의 위치는 (ri, ci), 질량은 mi이고, 방향은 di, 속력은 si이다. 위치 (r, c)는 r행 c열을 의미한다.

격자의 행과 열은 1번부터 N번까지 번호가 매겨져 있고, 1번 행은 N번과 연결되어 있고, 1번 열은 N번 열과 연결되어 있다.

파이어볼의 방향은 어떤 칸과 인접한 8개의 칸의 방향을 의미하며, 정수로는 다음과 같다.

7 0 1
6 2
5 4 3

마법사 상어가 모든 파이어볼에게 이동을 명령하면 다음이 일들이 일어난다.

  1. 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동한다.
    • 이동하는 중에는 같은 칸에 여러 개의 파이어볼이 있을 수도 있다.
  2. 이동이 모두 끝난 뒤, 2개 이상의 파이어볼이 있는 칸에서는 다음과 같은 일이 일어난다.
    1. 같은 칸에 있는 파이어볼은 모두 하나로 합쳐진다.
    2. 파이어볼은 4개의 파이어볼로 나누어진다.
    3. 나누어진 파이어볼의 질량, 속력, 방향은 다음과 같다.
      1. 질량은 ⌊(합쳐진 파이어볼 질량의 합)/5⌋이다.
      2. 속력은 ⌊(합쳐진 파이어볼 속력의 합)/(합쳐진 파이어볼의 개수)⌋이다.
      3. 합쳐지는 파이어볼의 방향이 모두 홀수이거나 모두 짝수이면, 방향은 0, 2, 4, 6이 되고, 그렇지 않으면 1, 3, 5, 7이 된다.
    4. 질량이 0인 파이어볼은 소멸되어 없어진다.

마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 구해보자.

입력

첫째 줄에 N, M, K가 주어진다.

둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다.

서로 다른 두 파이어볼의 위치가 같은 경우는 입력으로 주어지지 않는다.

출력

마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 출력한다.

🚀풀이

파이어볼이 움직일 때 한칸한칸 반복하면서 움직이면 연산이 느리다는걸 알았다.

for (int j = 0; j < temp[i].s; ++j)
{
	int ny = (temp[i].r + dy[temp[i].d] + N) % N;
	if (ny == 0)
		ny = N;
	temp[i].r = ny;
	int nx = (temp[i].c + dx[temp[i].d] + N) % N;
	if (nx == 0)
		nx = N;
	temp[i].c = nx;
}

이런식으로 코드를 짰는데 시간초과가 나왔다.

그래서 속도에 방향을 곱하는 방식으로 방법을 바꿨다.

for (int i = 0; i < temp.size(); ++i)
{
	int ny = (temp[i].r + dy[temp[i].d] * temp[i].s) % N;
	if (ny <= 0)
		ny += N;
	temp[i].r = ny;
	int nx = (temp[i].c + dx[temp[i].d] * temp[i].s) % N;
	if (nx <= 0)
		nx += N;
	temp[i].c = nx;
}

0이하인경우에는 N을 더해서 양수로 만들어줬다.

이 문제에서 파이어볼의 정보를 바로 지우게 된다면 좀 복잡해질거같아서 빈cBoard를 만들어서 풀었는데 메모리초과가 안났다.

그래서 움직이는 함수는 원복 board에서 복사를하고 움직이고 그값을 cBoard에 저장하는 방식으로 했다.
이렇게 한 이유는 파이어볼이 나눠질때 먼저 연산된 부분이 생기기때문이다.

나머지 부분은 걸리는거 없이 바로 풀었다!

image

🚀코드

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include<iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <math.h>

using namespace std;

struct FireBall
{
	int r, c, m, s, d;
};

int N, M, K, r, c, m, s, d;
int dy[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
int dx[] = { 0, 1, 1, 1, 0, -1, -1, -1 };
vector<FireBall> board[51][51];

void move_fireball()
{
	vector<FireBall> cBoard[51][51];
	for (int y = 1; y <= N; ++y)
	{
		for (int x = 1; x <= N; ++x)
		{
			if (board[y][x].size() == 0)
				continue;

			vector<FireBall> temp = board[y][x];
			board[y][x].clear();

			for (int i = 0; i < temp.size(); ++i)
			{
				int ny = (temp[i].r + dy[temp[i].d] * temp[i].s) % N;
				if (ny <= 0)
					ny += N;
				temp[i].r = ny;
				int nx = (temp[i].c + dx[temp[i].d] * temp[i].s) % N;
				if (nx <= 0)
					nx += N;
				temp[i].c = nx;

			}

			for (int i = 0; i < temp.size(); ++i)
			{
				cBoard[temp[i].r][temp[i].c].push_back(temp[i]);
			}
		}
	}

	for (int y = 1; y <= N; ++y)
	{
		for (int x = 1; x <= N; ++x)
		{
			for (int i = 0; i < cBoard[y][x].size(); ++i)
			{
				board[y][x].push_back(cBoard[y][x][i]);
			}
		}
	}
}

void merge_div_fireball()
{
	for (int y = 1; y <= N; ++y)
	{
		for (int x = 1; x <= N; ++x)
		{
			if (board[y][x].size() < 2)
				continue;

			vector<FireBall> temp = board[y][x];
			board[y][x].clear();
			int mSum = 0, sSum = 0, cnt = temp.size();
			int evenCnt = 0, oddCnt = 0;
			for (int i = 0; i < temp.size(); ++i)
			{
				if (temp[i].d % 2 == 0)
					evenCnt++;
				else
					oddCnt++;
				mSum += temp[i].m;
				sSum += temp[i].s;
			}

			// 그냥 소멸
			int mass = mSum / 5;
			if (mass == 0)
				continue;

			int speed = sSum / cnt;
			if (evenCnt == 0 || oddCnt == 0)
			{
				board[y][x].push_back({ y, x, mass, speed, 0 });
				board[y][x].push_back({ y, x, mass, speed, 2 });
				board[y][x].push_back({ y, x, mass, speed, 4 });
				board[y][x].push_back({ y, x, mass, speed, 6 });
			}
			else
			{
				board[y][x].push_back({ y, x, mass, speed, 1 });
				board[y][x].push_back({ y, x, mass, speed, 3 });
				board[y][x].push_back({ y, x, mass, speed, 5 });
				board[y][x].push_back({ y, x, mass, speed, 7 });
			}
		}
	}
}

void solve()
{
	cin >> N >> M >> K;

	for (int i = 1; i <= M; ++i)
	{
		cin >> r >> c >> m >> s >> d;
		board[r][c].push_back({ r, c, m, s, d });
	}

	for (int i = 1; i <= K; ++i)
	{
		move_fireball();
		merge_div_fireball();
	}

	int ret = 0;
	for (int y = 1; y <= N; ++y)
	{
		for (int x = 1; x <= N; ++x)
		{
			for (int i = 0; i < board[y][x].size(); ++i)
			{
				ret += board[y][x][i].m;
			}
		}
	}

	cout << ret;
}

int main()
{
	FILE* stream;
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	freopen_s(&stream, "input.txt", "rt", stdin);

	solve();

	return 0;
}