정말 많이 헤맸던 문제다.
그리고 자꾸 결과가 0으로만 나오는데, 문제가 어디인지 찾질 못해서 애를 먹었다.
아니 정확히 말하면 디버깅을 효과적으로 하지 못했기에,, 시간을 더 잡아먹은 것이다.
XCode도 이렇게 못 다루는데 Visual Studio는 어떻게 디버깅하지...
이번 문제는 이전 글인 2차원 배열 회전하기 를 활용했다.
핵심 Key Point는 이렇다.
1. 방향은 매번 '좌-하-우-상' 으로 전환된다.
2. 화살표의 길이는 1 -> 1 -> 2 -> 2 -> 3 -> 3 -> 4 -> 4 ... 이렇게 짝수번째 마다 증가한다.
3. 배열의 (0,0)에 도착하면 종료한다.
4. 화살표의 도착 지점만을 기준으로 계산하는 게 아니다
5. '버림'을 잘 기억해야 한다.
난 4번, 5번 부분을 헷갈려서 시간을 많이 잡아먹었다.
4번은.. 예를 들어 이번 턴에 3칸 이동한다고 해서, 도착지점인 딱 그 지점만을 기준으로 계산하는게 아니라,,, 한칸씩 세번 이동하면서 매 번 토네이도 흩뿌리기를 시전해야 한다. 이걸 이해하는 데에만 꽤 오랜 시간이 걸렸다.
5번은.. 계산 도중에 버림을 사용해야 한다는 지문을 잘 읽어야 한다. floor() 함수를 꼭 이용해주어야 한다.
int x double 의 결과는 double로 나오기 때문에 주의해야 한다.
/*
문제를 잘못 이해해서 계속해서 결과가 0이 나왔다.
도착지점 기준이 아니라, 움직이는 경로 한칸 한칸 마다 모두 계산해주어야 한다.
*/
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int N;
double f[5][5] = {
{0, 0, 0.02, 0, 0},
{0, 0.1, 0.07, 0.01 ,0},
{0.05, 99, 0, 0, 0},
{0, 0.1, 0.07, 0.01, 0},
{0, 0, 0.02, 0, 0}
};
int mx[4] = {0, 1, 0, -1};
int my[4] = {-1, 0, 1, 0};
int OUT_SAND = 0; // 밖을 나간 모래
// 반시계방향 90도 회전
void rotate() {
double tmp[5][5];
for(int i = 0; i < 5; i++) {
for(int j = 0; j < 5; j++) {
tmp[i][j] = f[j][5 - i - 1];
}
}
memmove(f, tmp, sizeof(f)); // dest, src, size
}
// a를 계산해줌
// 계속 0이나와서 멘탈이 흔들렸던 문제. 이유는 바로 이 함수가 문제였다
// (value * 퍼센트) * 2 작업 과정에서,
// value 정수가 퍼센트 소수를 곱한 결과는 소수가 나왔고, 거기에 *2까지 하니..
// 버림을 제대로 해주지 못한 결과가 도출된 것이다.
int calcuate_a(int value) {
// int니까 연산 도중 자동 버림 될듯.
value = value - (floor(value * 0.1) * 2 + floor(value * 0.07) * 2 + floor(value * 0.01) * 2 + floor(value * 0.02) * 2 + floor(value * 0.05));
return value;
}
// &는 참조로, 여기서 v의 값을 변경해도 원본까지 바뀐다~!
void M_SAND(int sx, int sy, vector<vector<int>>& v) {
int ORI_SAND = v[sx][sy];
v[sx][sy] = 0;
for(int i = -2; i <= 2; i++) {
for(int j = -2; j <= 2; j++) {
int percent = f[i + 2][j + 2];
int move_sand;
// double은 명확한 비교 안되니까, 10보다 크다 정도로 하면 99가 걸릴거
if(percent > 10) {
move_sand = calcuate_a(ORI_SAND);
} else {
move_sand = floor(ORI_SAND * f[i + 2][j + 2]);
}
if(i + sx < 0 || i + sx >= N || j + sy < 0 || j + sy >= N) {
// 밖을 나감
OUT_SAND += move_sand;
} else {
// 밖을 안나감
v[i + sx][j + sy] += move_sand;
}
}
}
}
int main() {
cin >> N;
vector<vector<int>> v(N, vector<int>(N, 0));
for(int i = 0; i < N; i++) {
for(int j = 0; j < N; j++) {
cin >> v[i][j];
}
}
int COUNT = 0; // 짝수가 될 때 마다 방향을 바꿀거임
int DIR = 0; // 방향
int LEN = 1; // 길이
// 출발지점
int sx = N / 2;
int sy = N / 2;
bool flag = false; // 종료 플래그
while(1) {
for(int i = 0; i < LEN; i++) {
sx = sx + mx[DIR];
sy = sy + my[DIR];
if(sx < 0 || sx >= N || sy < 0 || sy >= N) // 이런일은 없겠지만..
break;
M_SAND(sx, sy, v);
if(sx == 0 && sy == 0) {
flag = true;
break;
}
}
if(flag)
break;
COUNT++;
if(COUNT % 2 == 0) { // 짝수가 되면 길이 늘림
LEN++;
}
DIR = (DIR + 1) % 4; // 방향 전환
rotate();
}
cout << OUT_SAND << "\n";
}
결과가 계속 0이라면, floor를 이용한 버림이 잘 되지 않았을 가능성이 크다.
디버깅을 할 때, 모래가 매 순간 이동하는 경우를 프린트해보면 쉽게 문제를 찾을 수 있다.
난 엉뚱한 곳에서 브레이크를 걸고 디버깅해서 시간을 불필요하게 많이 잡아먹었다.
예제로 움직임에 대한 스냅샷을 그려주신 분이 있어서, 참고하면 좋을 것 같다.
https://velog.io/@jeewoo1025/백준-20057-마법사-상어와-토네이도
started at 21:40
ended at 24:40
참고하면 좋은 블로그
'[백준]' 카테고리의 다른 글
[BaekJoon/백준] 20056번 마법사 상어와 파이어볼 (0) | 2022.10.08 |
---|---|
[BaekJoon/백준] 21610번 마법사 상어와 비바라기 (0) | 2022.10.06 |
[BaekJoon/백준] 14890 경사로 (0) | 2022.08.05 |
[BaekJoon/백준] 5558번 Cheese (0) | 2022.08.04 |
[BaekJoon/백준] 1600번 말이 되고픈 원숭이 (0) | 2022.08.03 |