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

김정환·2022년 9월 21일

진짜 오랜만에 다시 삼성 기출을 풀어본다
오랜만에 푸니 너무 오래걸린다
총 4시간은 걸린 듯

//20057번 마법사 상어와 토네이도
#include <iostream>
using namespace std;

int N;
int y;
int x;
int dy[4] = { 0, 1, 0, -1 }; //서 남 동 북
int dx[4] = { -1, 0, 1, 0 };
//비율 열개 {1,1,7,7,10,10,2,2,5,a}
int rdy[4][10] = { 
	{-1,1,-1,1,-1,1,-2,2,0,0},
	{-1,-1,0,0,1,1,0,0,2,1},
	{-1,1,-1,1,-1,1,-2,2,0,0},
	{1,1,0,0,-1,-1,0,0,-2,-1} 
};
int rdx[4][10] = {
	{1,1,0,0,-1,-1,0,0,-2,-1},
	{-1,1,-1,1,-1,1,-2,2,0,0},
	{-1,-1,0,0,1,1,0,0,2,1},
	{-1,1,-1,1,-1,1,-2,2,0,0}
};
double spreadRate[9] = { 0.01,0.01,0.07,0.07,0.1,0.1,0.02,0.02,0.05 };
int map[503][503];
int totalOutSand = 0;

void Init() {
	for (int i = 0; i <= 500; i++) {
		for (int j = 0; j <= 500; j++) {
			map[i][j] = 0;
		}
	}
}

void BeforePrint() {
	cout << "Before Move Sand\n";
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			cout << map[i][j] << ' ';
		}
		cout << "\n";
	}
}

void SandPrint(int y, int x) {
	cout << "  Print Moved Sand\n";
	for (int i = 1; i <= N; i++) {
		cout << "  ";
		for (int j = 1; j <= N; j++) {
			if (i == y && j == x) {
				cout << map[i][j] << "^ ";
			}
			else {
				cout << map[i][j] << " ";
			}
		}
		cout << "\n";
	}
}

//dir 방향으로 이동할 (y,x)의 모래를 규칙에 맞게 뿌린다
//map[][]에 뿌린 후 모래량 표시
void SpreadSand(int y, int x, int dir) { 
	int totalMovedSand = 0;
	for (int i = 0; i < 10; i++) { //열번쨰는 a이니 확인 필요!!
		int movedSand;
		//바람에 의해 이동할 곳의 모래량
		if (i == 9) { //a인 부분
			movedSand = map[y][x] - totalMovedSand;
			//cout << map[y][x] << "모래에서 전체 비율모래량 "<<totalMovedSand<<"뺀 모래량 " << movedSand << "\n";
		}
		else { //나머지 비율부분
			movedSand = map[y][x] * spreadRate[i];
			//cout << map[y][x] << "모래의 " << spreadRate[i] << "비율의 모래 " << movedSand << "\n";
		}
		totalMovedSand = totalMovedSand + movedSand;


		int ny = y + rdy[dir][i];
		int nx = x + rdx[dir][i];
		//1,1 부터 N,N 격자 경계 벗어나면 모래 량 더해가기
		if (ny<1 || ny>N || nx<1 || nx>N) {
			totalOutSand = totalOutSand + movedSand;
			continue;
		}
		//경계 벗어나지 않으면 기존map[ny][nx] + 날아온 모래량
		map[ny][nx] = map[ny][nx] + movedSand;
	}
	map[y][x] = 0;
	//SandPrint(y,x);
	//cout << "totalOutSand: " << totalOutSand << "\n";
}

int ChangeDir(int dir) {
	int ndir = (dir + 1) % 4;
	return ndir;
}

void MoveTonado(int y, int x) {
	int ny = y;
	int nx = x;

	int distance = 1;
	int dir = 0; //서쪽 움직임으로 시작

	while (1) {
		if (distance == N) { //만약 N만큼 움직여야한다면 N-1만큼 움직이고 끝
			distance -= 1;
			break;
		}

		//같은 거리로 두번 움직이되, 한번 총거리 움직일때 마다 방향 바꾸기
		for (int i = 0; i < 2; i++) {
			for (int j = 1; j <= distance; j++) {
				ny = ny + dy[dir];
				nx = nx + dx[dir];
				//BeforePrint();
				SpreadSand(ny, nx, dir);
			}
			//Print();
			dir = ChangeDir(dir); //거리만큼 움직였으면 방향바꾸기
		}
		distance++; //같은 거리 두번 움직이면 거리 + 1

	}

	//마지막 거리 움직임 표현
	for (int j = 1; j <= distance; j++) {
		ny = ny + dy[dir];
		nx = nx + dx[dir];
		//BeforePrint();
		SpreadSand(ny, nx, dir);
		//MoveTest(ny, nx);
	}
	//Print();
	
}

void Input() {
	cin >> N;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			int tmp;
			cin >> tmp;
			map[i][j] = tmp;
		}
	}
}



int main() {
	Input();
	y = (N + 1) / 2;
	x = (N + 1) / 2;
	MoveTonado(y,x);
	//cout << "result: " << totalOutSand<<"\n";
	cout << totalOutSand;

}

다시 풀어본 횟수 : 0

  • 다시 풀때 고려해 볼 점
    **토네이도가 이동할 곳의 모래가 0일때, 즉 없는 경우에는 비율계산을 할 필요가 없다!
profile
지금부터라도 열심히 해보자

0개의 댓글