알고리즘 문제 풀이/BOJ

[backjoon]20056 마법사 상어와 파이어볼 java

v 2021. 4. 24. 16:00

Gold 5,

이 문제는 런타임에러가 굉장히 발목을 잡았는데, 모듈러연산을 이용하여 마법사 상어의 이동을 처리했다고 생각했는데 오산이었다.

스피드가 엄청나게 클 경우 모듈러 연산을 사용하여도 런타임 에러가 발생할 수 있다. 

파이어볼 문제에서는 맵을 중심으로 풀건지 파이어볼을 중심으로 풀 건지를 선택해야한다.

나의 경우엔 파이어볼 객체에 파이어볼의 위치도 넣어주면서 리스트로 관리하는 방식으로 코딩하였다.

예외 처리에 특히 주의한다면 큰 무리는 없는 문제라고 생각한다.

 

import java.io.*;
import java.util.*;

class Main {
	static int N, M, K, answer;
	static List<FireBall>[][] map;
	static int[][] dirs =  {{-1, 0},{-1, 1},{0, 1},{1,1},{1, 0},{1, -1},{0, -1},{-1, -1}};
	static List<FireBall> listFireBall;
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
		StringTokenizer st;
		st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		K = Integer.parseInt(st.nextToken());
		
		map = new LinkedList[N+1][N+1];
		for(int i = 1; i <= N; i++) {
			for(int j = 1; j <= N; j++) {
				map[i][j] = new LinkedList<>();
			}
		}
		listFireBall = new LinkedList<>();
		for (int i = 0; i < M; i++) {
			st = new StringTokenizer(br.readLine());
				int r = Integer.parseInt(st.nextToken());
				int c = Integer.parseInt(st.nextToken());
				int m = Integer.parseInt(st.nextToken());
				int s = Integer.parseInt(st.nextToken());
				int d = Integer.parseInt(st.nextToken());
				
				FireBall cur= new FireBall(r, c, m, s, d);
				listFireBall.add(cur);
		}
		while(K-- > 0) {
			move();
			chageFileBall();
		}
		System.out.println(count());
	}
	
	public static int count() {
		int result = 0;
		for(FireBall fb : listFireBall) {
			result += fb.m;
		}
		
		return result;
	}
	//볼을 나누는 메서드
	public static void chageFileBall() {
		listFireBall = new LinkedList<>();
		for (int i = 1; i<= N ; i++) {
			for (int j = 1; j <= N; j++) {
				
				if(map[i][j].size() == 0) continue;
				if(map[i][j].size() == 1) {
					listFireBall.add(map[i][j].get(0));
					continue;
				}
		
				int sumM = 0;
				int sumSpeed = 0;
				
                //방향이 홀수라면 감소 시킬 것. 초기값이나 0이 아니라면 방향의 홀짝이 다른 값.
				int dirCnt = map[i][j].size();
                
				for(FireBall fb : map[i][j]) {
					sumM += fb.m;
					sumSpeed += fb.s;
					if(fb.d % 2 == 1) dirCnt--;
				}

				sumM /=5;//총 질량
				sumSpeed /= map[i][j].size();
				if(sumM == 0) continue;
				
				int start = 1;
				int end = 7;
				if(dirCnt == 0 || dirCnt == map[i][j].size()) {
					start = 0;
					end = 6;
				}
				//공들을 위치에 넣어주는 부분으로 안 하는게 맞지만 해도 정답에는 이상없음.
				for (int dir = start; dir <= end; dir+=2) {
//					int nextR = i + dirs[dir][0];
//					int nextC = j + dirs[dir][1];
//					nextR %= N;
//					nextC %= N;
//					System.out.println(i+":"+j);
					listFireBall.add(new FireBall(i, j, sumM, sumSpeed, dir));
				}
			}
		}
	}
	
	
	public static void move() {
		map = new LinkedList[N+1][N+1];
		for(int i = 1; i <=N; i++) {
			for(int j = 1; j <=N; j++) {
				map[i][j] = new LinkedList<>();
			}
		}
		for(FireBall fireBall : listFireBall) {
			int r = fireBall.row;
			int c = fireBall.col;
			int m = fireBall.m;
			int s = fireBall.s;
			int d = fireBall.d;
            
			//배열 범위내로 들어오게 하기 위함.
			r += (dirs[d][0] *s) + N;
			c += (dirs[d][1] *s) + N;
			r %= N;
			c %= N;
			r = r == 0? N : r;
			c = c == 0? N : c;
			r = r < 0? r + N: r;
			c = c < 0? c + N: c;
			map[r][c].add(new FireBall(r, c, m, s, d));
		}
	}	
}
class FireBall{
	int row;
	int col;
	int m;
	int s;
	int d;
	FireBall(int r, int c, int m, int s, int d){
		this.row = r;
		this.col = c;
		this.m = m;
		this.s = s;
		this.d = d;
	}
}
반응형