[C++]백준20057번 마법사 상어와 토네이도
문제는 다음과 같다.
오늘은 백준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;
}