본문 바로가기

Algorithm/BOJ

[BOJ-20056][시뮬레이션] 마법사 상어와 파이어볼 - Java

문제 바로가기

 

20056번: 마법사 상어와 파이어볼

첫째 줄에 N, M, K가 주어진다. 둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다. 서로 다른 두 파이어볼의 위치�

www.acmicpc.net

복기 끝

애매~~하다~~~

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

public class Main {
	
	static class Fireball{
		int y, x, mass, s, d;

		public Fireball(int y, int x, int mass, int s, int d) {
			this.y = y; this.x = x; this.mass = mass; this.s = s; this.d = d;
		}
	}
	
	static int N, M, K;
	static List<Fireball>[][] map;
	static List<Fireball> list = new ArrayList<>();
	static int[] dy = {-1, -1, 0, 1, 1, 1, 0, -1};
	static int[] dx = {0, 1, 1, 1, 0, -1, -1, -1};
	
	public static void main(String[] args) throws IOException {
		input();
		
		System.out.println(solve());
	}
	
	public static int solve() {
		int answer = 0;
		
		for(int time = 0; time < K; time++) {

			// 파이어볼 이동
			for(Fireball cur : list) {
				int ny = (cur.y + N + dy[cur.d] * (cur.s % N)) % N;
				int nx = (cur.x + N + dx[cur.d] * (cur.s % N)) % N;
				
				cur.y = ny; cur.x = nx;
				
				map[ny][nx].add(cur);
			}
			
			// 파이어볼 두개 이상 든 곳에서 
			for(int i = 0; i < N; i++) {
				for(int j = 0; j < N; j++) {
					if(map[i][j].size() == 1) map[i][j].clear();
					if(map[i][j].size() < 2) continue;
					
					int massSum = 0, sSum = 0;
					
					boolean even = map[i][j].get(0).d % 2 == 0 ? true : false;
					boolean odd = map[i][j].get(0).d % 2 == 1 ? true : false;
					
					for(Fireball cur : map[i][j]) {
						massSum += cur.mass;
						sSum += cur.s;
						even = even & cur.d % 2 == 0 ? true : false;
						odd = odd & cur.d % 2  == 1 ? true : false;
						list.remove(cur);
					}
					
					int newMass = massSum / 5;
					int size = map[i][j].size();
					map[i][j].clear();
					
					if(newMass == 0) continue;
					int newS = sSum / size;
					
					
					if(even | odd) { 	// 0 2 4 6
						for(int k = 0; k < 8; k += 2) {
							list.add(new Fireball(i, j, newMass, newS, k));
						}
					} else {
						for(int k = 1; k < 8; k += 2) {
							list.add(new Fireball(i, j, newMass, newS, k));
						}
					}
				}
			}
		}
		
		for(Fireball cur : list) answer += cur.mass;
		
		return answer;
	}	

	public static void input() throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		
		N = Integer.parseInt(st.nextToken()); M = Integer.parseInt(st.nextToken()); K = Integer.parseInt(st.nextToken());
		map = new List[N][N];
		
		for(int i = 0; i < N; i++) {
			for(int j = 0; j < N; j++) map[i][j] = new ArrayList<>();
		}
		
		for(int i = 0; i < M; i++) {
			st = new StringTokenizer(br.readLine(), " ");
			list.add(new Fireball(Integer.parseInt(st.nextToken()) - 1, Integer.parseInt(st.nextToken()) - 1, Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken())));
		}
		
	}
}

 

요곳도 상반기에 비하면 아주 양반입니당..

먼저 List로 파이어볼들을 관리하고, 이걸로 이동한 위치를 2차원 List에서 위치시킨 뒤에 두개 이상인 곳에서 파이어볼을 나눠주면 됩니다. 

 

맵의 양쪽 끝이 이어져 있기 때문에 모듈러 연산을 사용해서 다음 위치를 구해주면 편합니다.

근데 여기가 문젭니다.. 속도가 옴청 클때는 N 한번 더해봤자 마이너스가 나서 런타임 에러가 떴는데... 코테 때도 속도에다가도 모듈러를 해줬는지 기억이 가물가물허네;;;

 

암튼.. 새로운 위치를 갱신하고 map에 넣어줍니다.

map은 항상 깨끗한 상태에서 맨 처음 list를 반복돌면서 새로운 위치를 구한 곳으로 넣어줄겁니다. 따라서 사이즈가 1일 때는 map[i][j].clear();를 해줘야 합니다.

 

새로운 파이어볼들의 방향을 정하기 위해 boolean 변수 odd랑 even을 뒀습니다. 얘들은 같은 위치의 파이어볼들의 위치가 모두 홀수이거나 짝수일 때만 true 값을 갖습니다. 요 둘을 | 해서 새로운 파이어볼들의 위치를 정할 수 있겠져. 새로운 친구들은 list에 꽂아줍시다.

 

위의 작업을 K번 돌려주고 나서 list에 있는 파이어볼들의 질량의 합을 구하면 끝입니다.

 

 

 

아~~~ 애매하네~~~

처리했겠지 ^^;;;;

화이팅 화이팅~~~