백준 17837번 새로운 게임 2 Java/자바 - 2019 삼성 SW 역량테스트 기출문제
문제
주어진 NxN 2차원 배열에서 체스 말판을 정해진 규칙에 따라 이동한다. 한 칸의 4개 이상의 말이 쌓이거나 이동 횟수가 1000이 넘어가면 게임이 끝난다.
접근
- 좌표(x, y) 마다 말판을 순서대로 저장할 자료구조와 말판의 정보를 위한 자료구조 필요
- 말판을 순서대로 하나씩 꺼내고 좌표(x,y)를 확인한다.
- 그 좌표에서 해당 말판위에 쌓인 말판을 함께 움직이는데 흰색 칸 또는 빨간색 칸에 따라 순서가 뒤바뀌는 것을 고려한다.
풀이
1번
public class NewGame2_17837 {
	static int n, k;
	static int [][] table = new int[12][12];
	static ArrayList<Integer>[][] order = new ArrayList[12][12];
	static ArrayList<P> list = new ArrayList<>();
	static int [] dx = {0, 0, -1, 1};
	static int [] dy = {1, -1, 0, 0};
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		k = sc.nextInt();
		for(int i=0 ; i<n ; i++) 
			for(int j=0 ; j<n ; j++)
				table[i][j] = sc.nextInt();
		for(int i=0 ; i<12 ; i++) 
			for(int j=0 ; j<12 ; j++)
				order[i][j] = new ArrayList<>();
		for(int i=0 ; i<k ; ++i) {
			int x = sc.nextInt();
			int y = sc.nextInt();
			int d = sc.nextInt();
			x--;
			y--;
			d--;
			list.add(new P(x, y, d));
			order[x][y].add(i);			
		}
		int time = 0;
		while(true) {
			time++;
			if (time > 1000) break;
			for (int i = 0; i < k; i++) {
				int y = list.get(i).y;
				int x = list.get(i).x;
				int ny = y + dy[list.get(i).d];
				int nx = x + dx[list.get(i).d];
				if (!(0 <= ny && ny < n && 0 <= nx && nx < n) || table[nx][ny] == 2) {
					list.get(i).d = change(list.get(i).d);
					ny = y + dy[list.get(i).d];
					nx = x + dx[list.get(i).d];
				}
				if (!(0 <= ny && ny < n && 0 <= nx && nx < n) || table[nx][ny] == 2) { 
					/* do nothing
					 * 벽을 만나고 되돌았을 경우 고 
					 */
				} else if (table[nx][ny] == 0) { //이동칸이 흰색
					int idx = -1;
					for (int j = 0; j < order[x][y].size(); j++) { //i to size 까지 모두 이동
						int cand = order[x][y].get(j);
						if (cand == i) {
							idx = j;
						}
						if (idx == -1)
							continue;
						list.get(cand).y = ny;
						list.get(cand).x = nx;
						order[nx][ny].add(cand);
						
						if (order[nx][ny].size() >= 4) {
							System.out.println(time);
							System.exit(0);
						}
					}
					
					int size = order[x][y].size(); //제거
					for (int j = idx; j < size; j++)
						order[x][y].remove(order[x][y].size() - 1);
				} else { //이동한 칸이 빨간색
					int idx = -1;
					
					for (int j = order[x][y].size() - 1; j >= 0; j--) { //역순을 위해 j==i 인덱스 찾기
						int cand = order[x][y].get(j);
						if (cand == i) {
							idx = j;
							break;
						}
					}
					
					for (int j = order[x][y].size() - 1; j >= idx; j--) { //마지막부터 j까지 역순으로 이동
						int cand = order[x][y].get(j);
						list.get(cand).y = ny;
						list.get(cand).x = nx;
						order[nx][ny].add(cand);
						if (order[nx][ny].size() >= 4) {
							System.out.println(time);
							System.exit(0);
						}
					}
					
					int size = order[x][y].size(); //제거
					for (int j = idx; j < size; j++)
						order[x][y].remove(order[x][y].size() - 1);
				}
			}
		}
		System.out.println(-1);		
		sc.close();
	}
	public static int change(int d) {
		if(d == 0) return 1;
		else if(d == 1) return 0;
		else if(d == 2) return 3;
		else return 2;
	}
}
class P {
	int x; int y; int d;
	P(int x, int y, int d){
		this.x = x; this.y = y; this.d = d;
	}
}
- order 은 좌표마다 말판의 순서를 기록하기 위한 자료구조 이고 list 는 말판의 정보를 담기위한 자료구조이다
- list에서 하나씩 꺼내고 말판의 이동방향에 따라 다음 칸을 결정
- (i) 파란 또는 벽 : 방향을 바꿔준 뒤 한번 더 움직여야함. 즉,, 두 번 충돌을 고려해야함
- (ii) 흰색 : 원래 있던 좌표에서 i번째의 말판 위치를 시작점을 찾고 (x,y) -> (nx,ny) 로 order에 갱신하고 이전의 기록은 제거한다.
- (iii) 빨간색 : 흰색과 비슷하다. 역순이므로 끝에서부터 j번째를 찾고 뒤에서부터 갱신하고 이전의 기록을 제거하면 된다.
이 문제는 simulation 문제인 것 같다. 자료구조의 변형을 통해 문제를 접근해야 쉽게 풀 수 있는 것 같다.
결론
- 삼성전자 들어가고 싶……..