[C++]백준20057번 마법사 상어와 토네이도

2 minute read

문제는 다음과 같다.

오늘은 백준20057번 마법사 상어와 토네이도 문제를 풀어보도록 하자. 작년 하반기 S전자 기출문제로 역시 시뮬레이션 문제이다. 또 Modulation 연산이 쓰였다. 역시 모듈러연산을 매우 좋아하는 삼성이다.

그냥 문제대로 구현하면 되는데 소용돌이 구현 + 각 방향별 퍼센트 분배를 잘 해야했다. 소용돌이는 다 구현할 줄 안다고 가정하고, 퍼센트 분배가 문제이다. 서,남,동,북을 각각 갈 때 퍼센트 비율이 달라진다.

따라서 난 서쪽, 남쪽으로 갔을 때 퍼센트 분배를 구현했다. 만일 동쪽으로 가야한다면 서쪽의 퍼센트 분배에 -1을 곱하면 반대방향으로 갈 수 있기 때문에 이렇게 구현했다.

그리고 당연한 말이지만 문제이해 를 잘 해야한다.. 처음 문제이해를 잘못해서 머리가 터질뻔했다. 그리고 알파의 범위를 체크하지 않아서 반례에 걸릴뻔 했다. 하지만 다행히 1트에 맞췄다!!

                                     [코드]
#include <iostream>
using namespace std;

int map[500][500];
int dir[4][2] = { {0,-1},{1,0},{0,1},{-1,0} };//서남동북
int w_e_dust[10][3] = { {-1,0,7},{1,0,7},{-2,0,2},{2,0,2},{-1,-1,10},{1,-1,10},{-1,1,1},{1,1,1},{0,-2,5},{0,-1,0} };//서
int n_s_dust[10][3] = { {0,-1,7},{0,1,7},{0,-2,2},{0,2,2},{-1,-1,1},{-1,1,1},{1,-1,10},{1,1,10},{2,0,5},{1,0,0} };//남
int N, answer = 0;

bool Inbound(int y, int x) {
	return y >= 1 && x >= 1 && y <= N && x <= N;
}

void check_dust(int wind_dir, int y, int x) {
	int temp_dust = 0; bool change = false;
	if (wind_dir == 0 || wind_dir == 2) {//서 or 동
		if (wind_dir == 2) { //동쪽이면 방향 전환
			for (int i = 0; i < 10; i++) {
				w_e_dust[i][0] *= -1;
				w_e_dust[i][1] *= -1;
			}
			change = true;
		}
		
		for (int i = 0; i < 9; i++) {//좌표 움직이기
			int my = y + w_e_dust[i][0];
			int mx = x + w_e_dust[i][1];

			if (Inbound(my, mx)) { //만약 안에 들어왔으면
				temp_dust += (map[y][x] * w_e_dust[i][2] * 0.01);
				map[my][mx] += (map[y][x] * w_e_dust[i][2] * 0.01);
			}
			else { //격자 밖이면?
				temp_dust += (map[y][x] * w_e_dust[i][2] * 0.01);
				answer += (map[y][x] * w_e_dust[i][2] * 0.01);
			}
		}
		if (Inbound(y + w_e_dust[9][0], x + w_e_dust[9][1])) {//알파지점
			map[y + w_e_dust[9][0]][x + w_e_dust[9][1]] += (map[y][x] - temp_dust);
		}
		else {
			answer += (map[y][x] - temp_dust);
		}

		if (change) {//방향전환 되돌려주기
			for (int i = 0; i < 10; i++) {
				w_e_dust[i][0] *= -1;
				w_e_dust[i][1] *= -1;
			}
		}
	}
	else if (wind_dir == 1 || wind_dir == 3) {//남 or 북
		if (wind_dir == 3) { //북쪽이면 방향 전환
			for (int i = 0; i < 10; i++) {
				n_s_dust[i][0] *= -1;
				n_s_dust[i][1] *= -1;
			}
			change = true;
		}

		for (int i = 0; i < 9; i++) {//좌표 움직이기
			int my = y + n_s_dust[i][0];
			int mx = x + n_s_dust[i][1];

			if (Inbound(my, mx)) { //만약 안에 들어왔으면
				temp_dust += (map[y][x] * n_s_dust[i][2] * 0.01);
				map[my][mx] += (map[y][x] * n_s_dust[i][2] * 0.01);
			}
			else { //격자 밖이면?
				temp_dust += (map[y][x] * n_s_dust[i][2] * 0.01);
				answer += (map[y][x] * n_s_dust[i][2] * 0.01);
			}
		}
		if (Inbound(y + n_s_dust[9][0], x + n_s_dust[9][1])) {//알파지점
			map[y + n_s_dust[9][0]][x + n_s_dust[9][1]] += (map[y][x] - temp_dust);
		}
		else {
			answer += (map[y][x] - temp_dust);
		}

		if (change) {//방향전환 되돌려주기
			for (int i = 0; i < 10; i++) {
				n_s_dust[i][0] *= -1;
				n_s_dust[i][1] *= -1;
			}
		}
	}
	map[y][x] = 0;
}

void blow_wind(int y, int x) {
	int cnt = 0, margin = 1;
	while (!(y == 1 && x == 0)) {
		for (int i = 0; i < margin; i++) {
			y += dir[cnt % 4][0];
			x += dir[cnt % 4][1];
			if (map[y][x] != 0) {
				check_dust(cnt % 4, y, x);
			}
		}
		cnt += 1;
		margin = cnt / 2 + 1;
	}
}

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

	cin >> N;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			cin >> map[i][j];
		}
	}
	blow_wind(N/2 + 1, N/2 + 1);
	cout <<answer;
}