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)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

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

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
developer-ellen

인간 디버거의 로그 찍기

알고리즘/알고리즘문풀

코드 트리 - 나무 박멸(46번)

2022. 10. 9. 14:00

❓ 문제 - 코드 트리(code tree) 나무 박멸 46번 - JAVA 풀이법

 

출처

(https://www.codetree.ai/frequent-problems/tree-kill-all/description)

 

코드트리

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

www.codetree.ai

 

 

 

📝 문제해결법

1. 문제

  • 나무의 성장 -> 나무의 번식 -> 최대 많은 나무를 죽일 제초제 뿌릴 위치 선정 -> 제초제 뿌림의 단계로 m년 진행했을 때 제초제로 죽인 나무의 수를 구하는 문제이다.

 

2. 해결 방법

  • 문제 구현 부분을 크게 나무의 성장 -> 나무의 번식 -> 최대 많은 나무를 죽일 제초제 뿌릴 위치 선정 -> 제초제 뿌림의 단계로 나눈다.
    • 나무의 성장은 grow() 함수, 나무의 번식은 moving() 함수, 제초제 위치 선정은 pick()함수, 제초제 뿌린 후 나무 죽이는 것은 main for문 안에서 처리한다.
  • grow() - 나무의 성장
    • map에 저장된 값을 기준으로 i, j행의 4방향으로 나무가 존재하는 것을 count한 후 그 값을 i, j에 더해준다.
  • moving() - 나무의 번식
    • 나무의 번식은 동시에 일으나므로 map2라는 2차원 배열을 하나 더 선언해서 번식된 나무의 값을 map2에 저장하고 map1에 더해줌으로써 처리한다.
    • 나무가 있는 곳을 기준으로 4방향(상, 하, 좌, 우)를 탐색하면서 칸이 빈 곳을 count 해주고, 그 값을 기준으로 현재 나무의 갯수 / count 된 수를 4방향(상, 하, 좌, 우)로 더해준다.
    • 이 때, 번식을 처리할 때 문제에서 주어진 경우로 빈 영역이고, 만약 제초자가 뿌려져 있다면 동시에 제초제를 뿌린 시점과 현재 시점의 기준 차이가 c 이상일 때만 번식할 수 있도록 구현했다.
    • 마지막에 동시 처리를 위해 map2에 번식된 나무 수를 다시 map1에 더해준다.
  • pick()  -제초제 위치 선정
    • 일단 ArrayList에 Node로 현재까지 구한 최대 나무를 죽일 수 있는 Node를 리스트에 넣어주는데, list를 만약 정렬한다면 죽일 수 있는 나무 수(최대), 그리고 나무 수가 같다면 행을 기준(최소)으로, 그 다음은 행이 같다면  열(최소)을 기준으로 정렬할 수 있도록 구현한다.
    • 2차원 배열로 map을 돌면서 대각선으로 k배의 길이만큼, 죽일 수 있는 나무 수를 카운트해서 최대 죽일 수 있는 나무 수를 구한다.
    • 이때, 제초제를 뿌릴 때 만약 탐색한 곳이 벽이거나 나무가 없는 곳이면 해당 영역까지만 탐색하고 그 이상은 탐색하지 않도록 하는 것이 구현 포인트이다.
  • 제초제 죽임 처리
    • die 2차원 배열에 최적의 제초제를 뿌린 위치를 기준으로 다시 대각선을 k의 거리만큼 제초제를 뿌리고 나무를 죽임처리(map의 값을 0으로) 해준다.
    • 이때, 제초제 위치 선정과 동일하게  벽이거나 나무가 없는 곳이라면 거기까지만 제초제를 뿌리고, 그 이상의 영역에서는 탐색을 멈추도록 구현하는 것이 포인트이다.

 

3. 느낀점

  • 2번째 케이스에서 자꾸 이상해서 출력 디버깅했더니 바로 해결했다.
  • 그리고 코드트리에서 돌려봤는데 7번 케이스에서.. 자꾸 틀리길래 ㅠ 문제를 다시 정확하게 읽어보면서 주어진 조건과 내 구현이 다른 점이 있는지 파악했고 바로 제초제를 뿌릴 때 나무가 없는 영역 이상의 곳은 더이상 뿌리지 않도록 하는 것을 빼먹었다. 이것을 바로 잡고 돌리니 통과!
  • 오랜만에 알고리즘을 풀어서 약간 감이 없는데 이렇게, 테케가 안 통과하면 문제를 다시 천천히 읽어보면서 문제에서 글자 하나라도 조건 뽑아서 구현이 적용되었는지 파악하는 습관은 좋은 것 같다.

 

 

💻 소스코드 (JAVA)

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


public class Solution_46 {
	public static int n, m, k, c;
	public static int[][] map;
	public static int[][] die;
	public static class Node implements Comparable<Node>{
		int x;
		int y;
		int cnt;
		public Node(int x, int y, int cnt) {
			this.x = x;
			this.y = y;
			this.cnt = cnt;
		}
		@Override
		public int compareTo(Node o) {
			if(this.cnt == o.cnt) {
				if(this.x == o.x) {
					return this.y - o.y;
				}
				return this.x - o.x;
			}
			return o.cnt - this.cnt;
		}
	}
	public static int[] dx = {-1, 1, 0, 0, -1, -1, 1, 1};
	public static int[] dy = {0, 0, -1, 1, -1, 1, -1, 1};
	
	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());
		k = Integer.parseInt(st.nextToken());
		c = Integer.parseInt(st.nextToken());
		map = new int[n][n];
		die = new int[n][n];
		long cnt = 0;
		
		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());
			}
		}
		
		for(int p=1;p<=m;p++) {
			// 나무의 성장
			grow();
			// 나무의 번식
			moving(p);
			

			// 제초제 위치 선정
			Node node = pick();
			cnt += node.cnt;
			
			// 제초제 뿌리기
			for(int d=4;d<8;d++) {
				for(int s=0;s<=k;s++) {
					int nx = node.x + dx[d]*s;
					int ny = node.y + dy[d]*s;
					if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
					die[nx][ny] = p;
					if(map[nx][ny] > 0) {
						if(nx == node.x && ny == node.y) continue; 
						map[nx][ny] = 0;
					} else {
						break;
					}
					
				}
			}
			map[node.x][node.y] = 0;


		}
		
		System.out.println(cnt);
	}
	
	public static Node pick() {
		ArrayList<Node> list = new ArrayList<>();
		int max = 0;
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				if(map[i][j] == -1) continue;
				int count = 0;
					
				for(int d=4;d<8;d++) {
					for(int s=0;s<=k;s++){
						int nx = i + dx[d]*s;
						int ny = j + dy[d]*s;
						if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
						if(map[nx][ny] > 0) { 
							count += map[nx][ny];
						} else {
							break;
						}
						
					}
				}
				count -= map[i][j]*3;

				if(count > max) {
					max = count;
					list.clear();
					list.add(new Node(i, j, count));
				} else if(count == max) {
					list.add(new Node(i, j, count));
				}
			}
		}
		
		if(list.size() != 0) Collections.sort(list);
		return list.get(0);
	}
	
	public static void moving(int p) {
		int[][] map2 = new int[n][n];
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				if(map[i][j] <= 0) continue;
				int count = 0;
				for(int d=0;d<4;d++) {
					int nx = i + dx[d];
					int ny = j + dy[d];
					if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
					if(map[nx][ny] == 0 && (die[nx][ny] == 0 || p - die[nx][ny] > c)) count++;
				}
				
				for(int d=0;d<4;d++) {
					int nx = i + dx[d];
					int ny = j + dy[d];
					if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
					if(map[nx][ny] == 0 && (die[nx][ny] == 0 || p - die[nx][ny] > c)) {
						map2[nx][ny] += (map[i][j] / count);
					}
				}
				
			}
		}

		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				map[i][j] += map2[i][j];
			}
		}
	}
	
	public static void grow() {
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				if(map[i][j] <= 0) continue;
				int count = 0;
				for(int d=0;d<4;d++) {
					int nx = i + dx[d];
					int ny = j + dy[d];
					if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
					if(map[nx][ny] > 0) count++;
				}
				map[i][j] += count;
			}
		}
		
	}

}

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

프로그래머스 코딩테스트 연습 - 디스크컨트롤러 (JAVA)  (0) 2022.10.30
2022 KAKAO TECH INTERNSHIP - 두 큐 합 같게 만들기 (JAVA)  (0) 2022.10.23
코드 트리 - 예술성(45번)  (0) 2022.10.09
코드 트리 - 술래잡기(44번)  (1) 2022.10.08
BOJ - 게임 개발 1516번 (JAVA)  (0) 2022.09.22
    '알고리즘/알고리즘문풀' 카테고리의 다른 글
    • 프로그래머스 코딩테스트 연습 - 디스크컨트롤러 (JAVA)
    • 2022 KAKAO TECH INTERNSHIP - 두 큐 합 같게 만들기 (JAVA)
    • 코드 트리 - 예술성(45번)
    • 코드 트리 - 술래잡기(44번)
    developer-ellen
    developer-ellen

    티스토리툴바