Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Archives
Today
Total
관리 메뉴

Life Engineering

[BOJ 17837] 새로운 게임 2 (Java) 본문

Problem Solving

[BOJ 17837] 새로운 게임 2 (Java)

흑개 2022. 2. 22. 22:15

https://www.acmicpc.net/problem/17837

 

17837번: 새로운 게임 2

재현이는 주변을 살펴보던 중 체스판과 말을 이용해서 새로운 게임을 만들기로 했다. 새로운 게임은 크기가 N×N인 체스판에서 진행되고, 사용하는 말의 개수는 K개이다. 말은 원판모양이고, 하

www.acmicpc.net

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main_BOJ_17837 {
	static int[] dr= {0,0,0,-1,1};
	static int[] dc= {0,1,-1,0,0};
	static int[] opposites= {0,2,1,4,3};
	static int N, K;
	static HorseList[][] hmap;	//map 위치에 있는  horse들 저장
	static Horse[] horses;	//horse들 정보
	static int[][] map;		//color 저장
	static int answer=0;
	public static void main(String[] args) throws IOException {
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st=new StringTokenizer(br.readLine());
		N=Integer.parseInt(st.nextToken());
		K=Integer.parseInt(st.nextToken());
		map=new int[N][N];
		horses=new Horse[K+1];
		hmap=new HorseList[N][N];
		for (int i=0; i<N; i++) {
			st=new StringTokenizer(br.readLine());
			for (int j=0; j<N; j++) {
				map[i][j]=Integer.parseInt(st.nextToken());
				hmap[i][j]=new HorseList();
			}
		}
		int r, c, d;
		for (int i=1; i<=K; i++) {
			st=new StringTokenizer(br.readLine());
			r=Integer.parseInt(st.nextToken())-1;
			c=Integer.parseInt(st.nextToken())-1;
			d=Integer.parseInt(st.nextToken());
			horses[i]=new Horse(r,c,d);
			hmap[r][c].li.add(i); //
		}
		for (int i=0; i<1000; i++) {
			if (turn()) {
				answer=i+1;
				break;
			}
		}
		System.out.println(answer==0 ? -1 : answer);
	}
	
	private static boolean check() {
		for (int i=0; i<N; i++) {
			for (int j=0; j<N; j++) {
				if (hmap[i][j].li.size()>=4) return true;
			}
		}
		return false;
	}

	private static boolean turn() {
		for (int i=1; i<=K; i++) {
			Horse h=horses[i];
			int r=h.r; 
			int c=h.c;
			int next_r=r+dr[h.d];
			int next_c=c+dc[h.d];
			if (!isValid(next_r, next_c) || map[next_r][next_c]==2) {		//벗어나는 경우, 파란색
				h.d=opposites[h.d];
				next_r=r+dr[h.d];
				next_c=c+dc[h.d];
				if (isValid(next_r, next_c) && map[next_r][next_c]!=2) {
					i--;		//한번 더 이동시키기
				}
			}
			else if (map[next_r][next_c]==0) {		//흰
				int loc=findNum(r, c, i);
				for (int j=loc; j<hmap[r][c].li.size(); j++) {
					int num=hmap[r][c].li.get(j);
					hmap[r][c].li.remove(j);
					hmap[next_r][next_c].li.add(num);
					horses[num].r=next_r;
					horses[num].c=next_c;
					j--;
				}
			}
			else if (map[next_r][next_c]==1) {		//빨
				int loc=findNum(r,c,i);
				int len=hmap[r][c].li.size();
				for (int j=len-1; j>=loc; j--) {
					int num=hmap[r][c].li.get(j);
					hmap[r][c].li.remove(j);
					hmap[next_r][next_c].li.add(num);
					horses[num].r=next_r;
					horses[num].c=next_c;
				}
			}
			if (check()) return true;
		}
		return false;
		
	}
	
	private static boolean isValid(int r, int c) {
		return r>=0 && c>=0 && r<N && c<N;
	}

	private static int findNum(int r, int c, int n) {
		for (int i=0; i<hmap[r][c].li.size(); i++) {
			if (n==hmap[r][c].li.get(i)) return i;
		}
		return -1;
	}
	public static class Horse{
		int r, c, d;
		public Horse(int r, int c, int d) {
			this.r = r;
			this.c = c;
			this.d = d;
		}
	}
	public static class HorseList{
		ArrayList<Integer> li;
		public HorseList() {
			li=new ArrayList<>();
		}
	}

}

구현+시뮬레이션 문제.

 

자료구조는 다음과 같이 정했다.

-각 말의 위치와 방향을 저장하는 1차원 배열 

-각 map의 위치에 존재하는 말 번호 리스트를 저장하고 있는 2차원 배열

 

1 turn 마다 1번부터 K번까지의 말들을 돌면서, 다음과 같이 움직여준다.

-파란색을 만날 경우 방향만 반대 방향으로 바꿔주고, 다음 갈 칸을 체크해 파란색이 아닐 경우 한번 더 이동시켜주기

-흰색을 만날 경우, 현재 말이 현재 있는 위치에서 몇번째 말인지 체크하고,

그 위치부터 시작해서 끝 위치까지 말부터 현재 위치에서 그 말을 빼주고, 새로운 위치에 말을 넣고, 말의 정보를 담고 있는 객체인 Horse의 위치 정보를 변경해준다. 이때 빼주는 연산이 있으므로 j-- 해서 remove 가 잘 되도록 한다. (주의)

-빨간색을 만날 경우, 이 역시 현재 말이 현재 있는 위치에서 몇번째 말인지 체크하고, 

역순으로 넣어야 하므로 끝 위치부터 시작해서 그 위치까지 흰색에서 했던 연산을 반복한다.

각 말을 움직일 때마다 check 함수를 호출해서 종료 조건이 되는지 확인한다.

 

remove 연산을 썼기 때문에 시간적으로 조금 아쉬운데,

다른 분들의 코드를 보니 (https://yabmoons.tistory.com/304)

흰색을 만날 경우, 새로운 위치에 삽입할 때=>현재 말이 현재 있는 위치에서 몇번째인지 구해줘서, 그 끝 위치까지 새로운 위치에 넣어주고

기존 위치에서 삭제할 때=>현재 말이 현재 있는 위치에서 "역순으로" 몇번째인지 구해줘서, 마지막 원소에서부터 그 위치까지 pop_back() 을 해주는 방식을 취하셨다.

 

반대인 빨간색을 만날 경우, 삽입할 때 흰색에서 삭제했던 것처럼 역순으로 접근해서 넣어주면 된다.

 

 

 

'Problem Solving' 카테고리의 다른 글

[BOJ 16236] 아기 상어 (Java)  (0) 2022.02.23
[BOJ 14499] 주사위 굴리기 (Java)  (0) 2022.02.23
[BOJ 12100] 2048 (Easy) (Java)  (0) 2022.02.21
[BOJ 15685] 드래곤 커브 (Java)  (0) 2022.02.21
[BOJ 15683] 감시 (Java)  (0) 2022.02.19