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

이성훈·2022년 3월 30일
0

문제

마법사 상어가 토네이도를 배웠고, 오늘은 토네이도를 크기가 N×N인 격자로 나누어진 모래밭에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c열을 의미하고, A[r][c]는 (r, c)에 있는 모래의 양을 의미한다.

토네이도를 시전하면 격자의 가운데 칸부터 토네이도의 이동이 시작된다. 토네이도는 한 번에 한 칸 이동한다. 다음은 N = 7인 경우 토네이도의 이동이다.

토네이도가 한 칸 이동할 때마다 모래는 다음과 같이 일정한 비율로 흩날리게 된다.

토네이도가 x에서 y로 이동하면, y의 모든 모래가 비율과 α가 적혀있는 칸으로 이동한다. 비율이 적혀있는 칸으로 이동하는 모래의 양은 y에 있는 모래의 해당 비율만큼이고, 계산에서 소수점 아래는 버린다. α로 이동하는 모래의 양은 비율이 적혀있는 칸으로 이동하지 않은 남은 모래의 양과 같다. 모래가 이미 있는 칸으로 모래가 이동하면, 모래의 양은 더해진다. 위의 그림은 토네이도가 왼쪽으로 이동할 때이고, 다른 방향으로 이동하는 경우는 위의 그림을 해당 방향으로 회전하면 된다.

토네이도는 (1, 1)까지 이동한 뒤 소멸한다. 모래가 격자의 밖으로 이동할 수도 있다. 토네이도가 소멸되었을 때, 격자의 밖으로 나간 모래의 양을 구해보자.

입력

첫째 줄에 격자의 크기 N이 주어진다. 둘째 줄부터 N개의 줄에는 격자의 각 칸에 있는 모래가 주어진다. r번째 줄에서 c번째 주어지는 정수는 A[r][c] 이다.

출력

격자의 밖으로 나간 모래의 양을 출력한다.

https://www.acmicpc.net/problem/20057

풀이

토네이도의 진행방향이 좌, 하, 우, 상 순서로 반복되므로,
이를나타내기위한 dx[4], dy[4] 벡터와
dir 변수(dx, dy의 인덱스)를 구했다.
여기서 한바퀴회전시, if문대신에 간단히 나타내기위해 (dir+2) % 4의 나머지연산을 사용했는데,

나머지연산사용시 (dir - 1) % 4 로하면 정확한값이 안나온다. 왠지모르겠ㅇ므
무조건 (dir + 3) % 4 로 양수가 나오게끔 코드를 짜야겠다.
또, (int)형으로 강제 형변환시키면 자동으로 소숫점 내림이된다.

#define _CRT_SECURE_NO_WARNINGS 
#include <bits/stdc++.h>
int n, **sand, dir=0; //밖으로나간양을 계산하기위해 4만큼더크게 생성
int limit[] = {0, 0, 0, 0}; //벽

int dx[] = {0, 1, 0, -1}; //좌하우상
int dy[] = {-1, 0, 1, 0};
void printAll();
void init();
void hurricane();
void sandFlying(int x, int y, int dir);

void calculate() {
	int res = 0;
	for (int k = 2; k <= n + 3; k++) {
		res += sand[0][k]; res += sand[1][k];
	}
	for (int k = 2; k <= n + 3; k++) {
		res += sand[k][n + 2]; res += sand[k][n + 3];
	}
	for (int k = n + 1; k >= 0 ; k--) {
		res += sand[n + 2][k]; res += sand[n + 3][k];
	}
	for (int k = n + 1; k >= 0; k--) {
		res += sand[k][0]; res += sand[k][1];
	}
	printf("%d", res);
}

void init() {
	scanf("%d", &n);
	sand = new int* [n + 4];
	for (int i = 0; i < n + 4; i++) {
		sand[i] = new int[n + 4];
		for (int j = 0; j < n + 4; j++)
			sand[i][j] = 0; //초기화
	}

	for (int i = 2; i < n + 2; i++)
		for (int j = 2; j < n + 2; j++)
			scanf("%d", &sand[i][j]);
}

void hurricane() {
	int x = (n + 4) / 2, y = (n + 4) / 2;
	limit[0] = (n + 4) / 2 - 2;
	limit[1] = (n + 4) / 2 + 2;
	limit[2] = (n + 4) / 2 + 2;
	limit[3] = (n + 4) / 2 - 2;
	int cnt = n * n - 1;
	while (cnt--) {
		int xx = x + dx[dir];
		int yy = y + dy[dir];
		if ((dir == 0 && limit[dir] == yy) || //턴을해야하는상황이면
			(dir == 1 && limit[dir] == xx) ||
			(dir == 2 && limit[dir] == yy) ||
			(dir == 3 && limit[dir] == xx)) {
			if (dir == 0) limit[dir]--;
			if (dir == 1) limit[dir]++;
			if (dir == 2) limit[dir]++;
			if (dir == 3) limit[dir]--;

			dir = (dir + 1) % 4; //방향전환
			xx = x + dx[dir]; //다음위치 재설정
			yy = y + dy[dir]; 
		}

		x = xx;
		y = yy;
		sandFlying(x, y, dir);
	}

	calculate();
}

void sandFlying(int xx, int yy, int ddir) {
	int amount = sand[xx][yy]; //모래의양
	sand[xx][yy] = 0; 
	int a=(int)(amount * 0.1), b=(int)(amount * 0.01),
		c=(int)(amount * 0.02), d=(int)(amount * 0.07),
		e=(int)(amount * 0.05);

	if (dir % 2 == 0) { //좌 우
		sand[xx + dx[(ddir + 3) % 4]][yy + dy[ddir]] += a;
		sand[xx + dx[(ddir + 3) % 4]][yy + dy[(ddir + 2) % 4]] += b;
		sand[xx + 2 * dx[(ddir + 3) % 4]][yy] += c;
		sand[xx + dx[(ddir + 3) % 4]][yy] += d;

		sand[xx][yy + 2 * dy[ddir]] += e;

		sand[xx + dx[(ddir + 1) % 4]][yy] += d;
		sand[xx + 2 * dx[(ddir + 1) % 4]][yy] += c;
		sand[xx + dx[(ddir + 1) % 4]][yy + dy[(ddir + 2) % 4]] += b;
		sand[xx + dx[(ddir + 1) % 4]][yy + dy[ddir]] += a;
	}
	else { //하 상
		sand[xx + dx[ddir]][yy + dy[(ddir + 3) % 4]] += a;
		sand[xx + dx[(ddir + 2) % 4]][yy + dy[(ddir + 3) % 4]] += b;
		sand[xx][yy + 2 * dy[(ddir + 3) % 4]] += c;
		sand[xx][yy + dy[(ddir + 3) % 4]] += d;

		sand[xx + 2 * dx[ddir]][yy] += e;

		sand[xx][yy + dy[(ddir + 1) % 4]] += d;
		sand[xx][yy + 2 * dy[(ddir + 1) % 4]] += c;
		sand[xx + dx[(ddir + 2) % 4]][yy + dy[(ddir + 1) % 4]] += b;
		sand[xx + dx[ddir]][yy + dy[(ddir + 1) % 4]] += a;
	}

	amount = amount - (a + b + c + d + e + d + c + b + a);
	//알파
	sand[xx + dx[ddir]][yy + dy[ddir]] += amount;
}

int main(void) {
	init();
	hurricane();

	return 0;
}
profile
I will be a socially developer

0개의 댓글