developer-ellen
인간 디버거의 로그 찍기
developer-ellen
전체 방문자
오늘
어제
  • 분류 전체보기 (217)
    • 회고록 (0)
    • 취뽀 및 커리어 여정의 Stack (2)
      • SSAFY 7기 (2)
    • 프로그래밍공부 (24)
      • c++ (0)
      • JAVA (3)
      • Spring (5)
      • design pattern (3)
      • BackDB (1)
      • Servlet&JSP (3)
      • Vue (4)
      • JPA (4)
      • Infra (1)
      • Linux (0)
    • AI (3)
      • papers (3)
      • trend (0)
    • 프로젝트진행 (0)
      • 데이터베이스 (0)
      • 서버개발 (0)
      • 인공지능 (0)
      • 하루정리 (0)
    • 포트폴리오 (0)
    • 알고리즘 (158)
      • 알고리즘문풀 (155)
      • 알고리즘공부 (3)
    • 통계공부 (15)
      • 시계열분석 (15)
      • 회귀분석 (0)
    • CS (14)
      • 컴퓨터네트워크 (4)
      • 운영체제 (8)
      • 데이터베이스 (2)
    • 주저리주저리 (0)
      • 필사 (0)
    • 취업관련정보 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • c++디자인패턴
  • 시계열
  • 삼성코테준비
  • 통계학
  • 삼성코테기출
  • 삼성코테자바꿀팁
  • 삼성코테파이썬풀이
  • 데이터분석
  • 삼성코테자바준비
  • 운영체제인터럽트
  • 삼성코테구현풀이
  • MA모형
  • 카카오코테
  • ARIMA모형
  • SW역량테스트파이썬풀이
  • 삼성코테파이썬
  • AR모형
  • SW역량테스트파이썬
  • Arima
  • 시계열분석
  • c++ 빌더 패턴
  • 삼성코테자바풀이
  • 카카오코테java풀이
  • 삼성코테기출자바풀이
  • 삼성코테파이썬준비
  • 코테파이썬
  • BOJ파이썬풀이
  • 통계분석
  • 백준파이썬풀이
  • 삼성코테구현문제추천

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
developer-ellen

인간 디버거의 로그 찍기

코드 트리 - 술래잡기(44번)
알고리즘/알고리즘문풀

코드 트리 - 술래잡기(44번)

2022. 10. 8. 16:20

❓ 문제 - 코드 트리(code tree) 술래잡기 44번 - JAVA 풀이법

 

출처

(https://www.codetree.ai/frequent-problems/hide-and-seek/description)

 

코드트리

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

 

 

📝 문제해결법

1. 문제

  • 1회 안에 술래와의 거리가 3이하인 도망자들이 도망을 다니고 그 다음에 술래가 해당하는 방향에 맞춰 한 칸 이동한 후 시야가 3이하인 술래들을 잡을 수 있다. 이때 k번 술래의 이동동안 획득되는 점수를 구하여라.

 

2. 해결 방법

  • 우선 5 <= n <= 99, 1 <= m, h <= n^2 이고 문제에서 주어진 조건대로 로직을 돌렸을 때 얻어지는 값을 구해야하므로 전형적인 시뮬레이션 문제이다.
  • 1번의 이동은 술래와 거리가 3이하인 도망자들의 도망 -> 술래가 달팽이 모양으로 한 칸 이동 -> 현재 보는 시야에서 자신이 포함하는 위치를 포함하여 거리가 3이하인 술래를 잡기가 이면 이것에 맞춰 일단 k번 이동 시키면 된다.
  • 술래는 도망자를 기준으로 거리를 구해야하고, 도망자는 특정 이동 방향을 갖고 있으므로 ArrayList<Integer>의 2차원 배열 통해 도망자의 좌표 x, y 뿐만 아니라 방향에 대한 정보도 저장한다. -> 도망자는 이동하다가 한 영역에 여러 명이 존재할 수 있기 때문에 ArrayList를 활용한다.
  •  그리고 도망자가 이동할 때 한번에 이동된 후의 정보를 다른 ArrayList<Integer>[][]에 저장해뒀다가 한 번에 원래의 도망자의 위치를 기록하는 ArrayList<Integer>[][]에 다시 복사해준다.
  • 도망자가 도망갈 때 유의해야 하는 점은 주어진 문제의 조건이며, 이것을 잘 고려해서 구현에 적용해야한다.
    • 도망자가 우선 술래와의 거리가 3초과라면 현재 자신이 있는 위치에 그대로 다시 존재해야 한다.
    • 도망자가 술래와의 거리가 3이하라면
      • 자신의 방향에 맞추어 이동할 때 격자를 넘어가는 범위라면 상->하, 하->상, 좌->우, 우->좌로 방향 전환을 시켜주고 만약 방향 전환 시켜주고 한 칸을 이동할 때 술래가 없다면 그 곳으로 이동 처리해준다.
      • 만약 격자도 벗어나서 방향 전환 후 한 칸을 이동할 곳에 술래가 있다면 이동 처리 없이 원래 있는 위치에 방향만 바꿔서 값을 저장한다.
      • 만약 격자를 넘어가지 않고 이동방향에 맞춰 이동하려는데 술래가 있다면 그자리에 있고, 술래가 없다면 이동처리 해서 값을 저장한다.
  • 술래의 이동이다.
    • 술래는 달팽이 모양으로 이동하는데 밑에서 시야를 기준으로 술래를 잡기 때문에 이 부분을 잘 구현해야하는 것이 특징이다. 
    • 그리고 이 문제의 특별한 점은 달팽이로 움직이고 1,1 의 위치에서 다시 반대 방향으로 중앙 위치로 돌아오는 특징이 있다. 이런 방향에 대한 것을 원래 방향으로 움직일 때의 방향 정보를 c_map1, 반대 방향으로 돌아올 때의 방향 정보를 c_map2로 저장하여 해당 방향 정보를 기준으로 이동 처리 및 도망자를 잡는데 방향을 활용한다.

  • 중앙(n/2+1, n/2+1) 위치에서 달팽이 이동이 시작될 때 방향의 변환은 규칙적으로 상(0) -> 우(1) -> 하(2) -> 좌(3)로 이루어진다.
  • 방향의 전환은 상->우->하->좌를 반복하면서 1, 1, 2, 2, 3, 3, 4, 4, ..., n 칸씩 각 방향에 맞춰 이동했을 때 방향 전환이 이루어진다. 이것을 이중 while문을 통해서 이동 칸수를 count하면서 방향 전환을 시켜주고 방향에 대한 정보를 2차원 배열에 저장한다.
  • 반대 방향으로 돌아올 때는 방향을 구하면 기존에 이동방향에 반대로, 상(0)->하(2), 하(2)->상(0), 우(1)->좌(3), 좌(3)->우(1) 이므로 이것을 처리해서 c_map1를 구할 때 동시에 c_map2를 구한다.
  • c_map2를 구할 때 유의할 점은 c_map1에서 달팽이를 돌다가 빨간 화살표처럼 방향을 바꾸는 위치에서는 기존 방향의 반대가 아닌, 상(0)->우(1), 우(1)->하(2), 하(2)->좌(3), 좌(3)->상(0)로 변환 처리 한다.
  • 그리고 c_map1이든 c_map2이든 1,1과 중앙(n/2+1, n/2+1)의 이동방향은 같기 때문에 하(2), 상(0)로 지정해둬야 한다. 
  • 그리고 k번 이동하면서 이동처리를 위해 1,1에 도착했을 때 turn을 true로 바꾸고, 중앙(n/2+1, n/2+1)로 도착했을 때 turn의 값을 false로 바꿔서, turn이 false일 때는 c_map1 사용하고, turn이 true일 땐 c_map2를 사용하도록 구현했다.
  • 술래가 바라보는 시야로 도망자 잡기
    • c_map1과 c_map2를 활용해서 현재 바라보는 시야로 현재 위치를 기준으로 거리가 3이하에 있는 몬스터를 잡도록 구현한다.
    • 몬스터가 만약 트리와 같이 있지 않고 거리가 3이하에 있다면 몬스터의 숫자를 카운터 해주고 몬스터를 clear해줘서 잡도록 한다.
    • 그리고 점수를 증가시킬 때는 현재 진행중인 이동 숫자 p * 잡은 몬스터 수를 더해주면서 갱신해준다.

 

3. 느낀점

  • 상반기때 하나의 예외케이스를 처리 못해서..코테 광탈한 문제 ㅠㅠ
  • 코드트리로 그래도 5시간동안 다시 그 때의 잘못을 짚어가면서 풀었더니 그래도 해결되었다..
  • 그 때 이런식으로 빡구현하는 게 맞는 건가 의문이 들었는데.. 그게 맞았다
  • 앞으로 이런 빡구현할 때 더 상황에 대해 나눠서 구현 계획을 세워야겠다..

 

 

💻 소스코드 (JAVA)

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

public class Solution_44 {


	public static int[] dx = {0, 0, 1, -1};
	public static int[] dy = {1, -1, 0, 0};
	
	public static int[] c_dx = {-1, 0, 1, 0};
	public static int[] c_dy = {0, 1, 0, -1};
	
	public static int[][] c_map1;
	public static int[][] c_map2;
	public static int n, m, h, k;
	public static ArrayList<Integer>[][] m_map;
	public static boolean[][] tree;
	
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
	
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());
		h = Integer.parseInt(st.nextToken());
		k = Integer.parseInt(st.nextToken());
		boolean turn = false;
		m_map = new ArrayList[n+1][n+1];
		c_map1 = new int[n+1][n+1];
		c_map2 = new int[n+1][n+1];
		tree = new boolean[n+1][n+1];
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=n;j++) {
				m_map[i][j] = new ArrayList<Integer>();
			}
		}
		
		for(int i=0;i<m;i++) {
			st = new StringTokenizer(br.readLine(), " ");
			int x = Integer.parseInt(st.nextToken());
			int y = Integer.parseInt(st.nextToken());
			int dir = Integer.parseInt(st.nextToken());
			
			if(dir==1){
				m_map[x][y].add(0);
			} else {
				m_map[x][y].add(2);
			}
		}
		
		for(int i=0;i<h;i++) {
			st = new StringTokenizer(br.readLine(), " ");
			int x = Integer.parseInt(st.nextToken());
			int y = Integer.parseInt(st.nextToken());
			tree[x][y] = true;
		}
		
		int nx = n/2 +1;
		int ny = n/2 +1;
		int d = 0;
		int num = 1;
		outer: while(true) {
			int cnt = 0;
			int same_cnt = 0;
			while(true) {
				nx += c_dx[d];
				ny += c_dy[d];
				c_map1[nx][ny] = d;
				c_map2[nx][ny] = (d+2)%4;
				cnt++;
				if(cnt == num) {
					d = (d+1) % 4;
					c_map1[nx][ny] = d;
					c_map2[nx][ny] = (d+1)%4;
					cnt = 0;
					if(num == n) {
						break outer;
					}
					if(same_cnt == 0) {
						same_cnt++;
					} else {
						num++;
						same_cnt = 0;
						break;
					}
				} 
			}
		}
		
		c_map1[1][1] = 2;
		c_map2[1][1] = 2;
		
		int x = n/2 + 1;
		int y = n/2 + 1;
		int dir = 0;
		int sum = 0;
		for(int p=1;p<=k;p++) {

			// 도망자 이동
			ArrayList[][] monster = new ArrayList[n+1][n+1];
			for(int i=1;i<=n;i++) {
				for(int j=1;j<=n;j++) {
					monster[i][j] = new ArrayList<Integer>();
				}
			}
			for(int i=1;i<=n;i++) {
				for(int j=1;j<=n;j++) {
					if(m_map[i][j].size() == 0) continue;
					for(int n_d:m_map[i][j]) {
						if(Math.abs(i-x) + Math.abs(j-y) <= 3) {
							// 1칸 이동 -> 격자
							int ni = i + dx[n_d];
							int nj = j + dy[n_d];
								
							if(ni < 1 || ni > n || nj < 1 || nj > n) {
								if(n_d % 2 == 0) {
									n_d++;
								} else {
									n_d--;
								}
								
								if(x != ni+dx[n_d] || y != nj+dy[n_d]) {
									ni = i + dx[n_d];
									nj = j + dy[n_d];
								} 
							} 
							if(x != ni || y != nj) {
								monster[ni][nj].add(n_d);
							} else {
								monster[i][j].add(n_d);
							}
						
						} else {
							monster[i][j].add(n_d);
						}
					}
					
				}
			}
			for(int i=1;i<=n;i++) {
				for(int j=1;j<=n;j++) {
					m_map[i][j] = monster[i][j];
				}
			}
			
			
			if(!turn) {
				dir = c_map1[x][y];
				x += c_dx[dir];
				y += c_dy[dir];
				dir = c_map1[x][y];
			} else {
				dir = c_map2[x][y];
				x += c_dx[dir];
				y += c_dy[dir];
				dir = c_map2[x][y];
			}
			if((x == 1 && y == 1) || (x == (n/2+1) && y == (n/2+1))) {
				turn = turn?false:true;
			}
			//System.out.println(dir+" "+x+" "+y);
			int count = 0;
			// 점수 획득
			for(int s=0;s<=2;s++) {
				int s_x = x + c_dx[dir] * s;
				int s_y = y + c_dy[dir] * s;
				if(s_x < 1 || s_x > n || s_y < 1 || s_y > n) continue;
				if(m_map[s_x][s_y].size() != 0 && !tree[s_x][s_y]) {
					count += m_map[s_x][s_y].size();
					m_map[s_x][s_y].clear();
					
				}
			}
			sum += (p*count);
		}
		
		System.out.println(sum);
		
	}
}

'알고리즘 > 알고리즘문풀' 카테고리의 다른 글

코드 트리 - 나무 박멸(46번)  (0) 2022.10.09
코드 트리 - 예술성(45번)  (0) 2022.10.09
BOJ - 게임 개발 1516번 (JAVA)  (0) 2022.09.22
BOJ - 네트워크 복구 2211번 (JAVA)  (0) 2022.09.18
BOJ - 우주신과의 교감 1774번 (JAVA)  (0) 2022.09.10
    '알고리즘/알고리즘문풀' 카테고리의 다른 글
    • 코드 트리 - 나무 박멸(46번)
    • 코드 트리 - 예술성(45번)
    • BOJ - 게임 개발 1516번 (JAVA)
    • BOJ - 네트워크 복구 2211번 (JAVA)
    developer-ellen
    developer-ellen

    티스토리툴바