티스토리 뷰

IT/골드5

백준 문제풀이 (골드 5)

Stv 2023. 1. 31. 13:35

목차


    1. 토마토(7569)

    👉 소스코드

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.util.*;
    
    import javax.swing.plaf.synth.SynthSeparatorUI;
    
    
    public class Main {
    	static int width, height, H, notT = 0, count = 0; 
    	static int[][][] arr;
    	static int[] moveX =  {-1, 1, 0, 0, 0, 0};
    	static int[] moveY =  {0, 0, -1, 1, 0, 0};
    	static int[] moveH =  {0, 0, 0, 0, -1, 1};
    	static Queue<int[]> okT = new LinkedList<int[]>();
    	
    	public static void main(String[] args) throws Exception{
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		StringTokenizer st = new StringTokenizer(br.readLine());
    		
    		width = Integer.parseInt(st.nextToken());
    		height = Integer.parseInt(st.nextToken());
    		H = Integer.parseInt(st.nextToken());
    		
    		arr = new int[H][height][width];
    		
    		for(int i = 0; i < H; i++) {
    			for(int j = 0; j < height; j++) {
    				String[] tmp = br.readLine().split(" ");
    				for(int k = 0; k < width; k++) {
    					arr[i][j][k] = Integer.parseInt(tmp[k]);
    					if(Integer.parseInt(tmp[k]) == 0) {
    						notT++;
    					}else if(Integer.parseInt(tmp[k]) == 1) okT.offer(new int[]{i, j, k});
    				}
    			}
    		}
    		bfs();
    		System.out.println(notT == 0 ? count : -1);
    	}
    	
    	public static void bfs() {
    		while(notT > 0 && !okT.isEmpty()) {
    			int size = okT.size();
    			for(int i = 0; i < size; i++) {
    				int c = okT.peek()[0];
    				int b = okT.peek()[1];
    				int a = okT.peek()[2];
    				okT.poll();
    				for(int j = 0; j < 6; j++) {
    					int nC = c + moveH[j];
    					int nB = b + moveY[j];
    					int nA = a + moveX[j];
    					
    					if(nA < 0 || nB < 0 || nC < 0 || nA >= width || nB >= height || nC >= H) {
    						continue;
    					}else if(arr[nC][nB][nA] != 0) 
    						continue;
    					notT--;
    					arr[nC][nB][nA] = 1;
    					okT.offer(new int[] {nC, nB, nA});
    				}
    			}
    			count++;
    		}
    	}
    }

    2. 적록색약(10026)

    👉 소스코드

    import java.util.*;
    import java.io.*;
    public class Main {
    
    	static int N;
    	static char[][] arr;
    	static boolean[][] visited;
    	static int[] moveN = { 0, 0, -1, 1 }, moveM = { -1, 1, 0, 0 };
    
    	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());
    		
    		arr = new char[N][N];
    		visited = new boolean[N][N];
    		
    		for(int i = 0; i < N; i++) {
    			arr[i] = br.readLine().toCharArray();
    		}
    		
    		// 일반인 대상 
    		int totalCount = 0;
    		for(int i = 0; i < N; i++) {
    			for(int j = 0; j < N; j++) {
    				
    				char c = arr[i][j];
    				if(!visited[i][j]) {
    					bfs(i, j, c);
    					totalCount++;
    				}
    				// 일반인 대상 탐색한 후, 적록색약자 탐색하기 위해 변경해줌
    				if(arr[i][j] == 'R') arr[i][j] = 'G'; 
    			}
    		}
    		
    		visited = new boolean[N][N];
    		
    		// 적록색약자 대상
    		int rgCount = 0;
    		for(int i = 0; i < N; i++) {
    			for(int j = 0; j < N; j++) {
    				
    				char c = arr[i][j];
    				if(!visited[i][j]) {
    					bfs(i, j, c);
    					rgCount++;
    				}
    			}
    		}
    		System.out.println(totalCount + " " + rgCount);
    		
    	}
    	
    	public static void bfs(int x, int y, char color) {
    		Queue<int[]> q = new LinkedList<int[]>();
    		q.offer(new int[] {x, y});
    		visited[x][y] = true;
    		
    		
    		while(!q.isEmpty()) {
    			
    			int curX = q.peek()[0];
    			int curY = q.peek()[1];
    			q.poll();
    			
    			for(int i = 0; i < 4; i++) {
    				int nextX = curX + moveN[i];
    				int nextY = curY + moveM[i];
    				
    				if(nextX < 0 || nextY < 0 || nextX >= N || nextY >= N || visited[nextX][nextY]) continue;
    				
    				if(arr[nextX][nextY] == color) {
    					visited[nextX][nextY] = true;
    					q.offer(new int[] {nextX, nextY});
    				}
    				
    			}
    			
    		}
    	}
    }

    - 일반인 대상으로 먼저 탐색 시작

    인접한 영역에 같은 색이 있는지 찾고 탐색이 끝나면 적록색약자를 탐색하기 위하여 'R'와 'G'를 한가지 색상으로 변경해주었다.

    변경하고 난 맵을 다시한번 더 탐색

    - 아래는 dfs로 풀이

    public static void dfs(int x, int y, char color) {
        visited[x][y] = true;
    
        for(int i = 0; i < 4; i++) {
    
            int nextX = x + moveN[i];
            int nextY = y + moveM[i];
    
            if(nextX < 0 || nextY < 0 || nextX >= N || nextY >= N || visited[nextX][nextY]) continue;
    
            if(arr[nextX][nextY] == color) {
                dfs(nextX, nextY, color);
            }
        }
    }

    3. 4연산(14395)

    👉 소스코드

    import java.util.*;
    import java.io.*;
    public class Main {
    
    	static int S, T;
    	static HashSet<Integer> set = new HashSet<Integer>();
    	static StringBuilder sb = new StringBuilder();
    	static long[] visited;
    	
    	public static void main(String[] args) throws Exception {
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		StringTokenizer st = new StringTokenizer(br.readLine());
    		
    		S = Integer.parseInt(st.nextToken());
    		T = Integer.parseInt(st.nextToken());
    		
    		if(S == T) {
    			System.out.println(0);
    		}else if(T == 1){
    			System.out.println("/");
    		}else {
    			bfs(S);
    		}
    	}
    	
    	public static void bfs(int start) {
    		Queue<Cal> q = new LinkedList<Cal>();
    		q.offer(new Cal(start, ""));
    		set.add(start);
    		
    		while(!q.isEmpty()) {
    			Cal c = q.poll();
    			
    			String operator = c.value;
    			
    			if(c.num == T) {
    				if(!set.contains(T)) {
    					System.out.println("-1");
    				}else{
    					System.out.println(operator);
    				}
    				return; 
    			}
    			for(int i = 0; i < 3; i++) {
    				long number = c.num;
    				
    				if(i == 0) number *= number;
    				else if(i == 1) number += number;
    				else if(i == 2) number /= number;
    				
    				if(set.contains((int)number)) continue;
    				
    				if(number > T) continue;
    				
    				if(i == 0) q.offer(new Cal((int)number, operator + "*"));
    				else if(i == 1) q.offer(new Cal((int)number, operator + "+"));
    				else if(i == 2) q.offer(new Cal((int)number, operator + "/"));
    				
    				set.add((int) number);
    			}
    		}
    		System.out.println(-1);
    	}
    	
    	static class Cal {
    		int num;
    		String value;
    		
    		public Cal (int num, String value) {
    			this.num = num;
    			this.value = value;
    		}
    	}
    }

    - 10⁹ 라는 제한이 있어서 배열로 방문처리하기에는 무리가 있어 연산한 수에 대하여 set으로 방문 처리를 했다.

    이미 있으면 set에 담지 않고 연산한 수와, String에 연산자를 큐에 담아서 풀이를 진행하였다.

     

    4. 로봇 청소기14503)

    👉 소스코드

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.StringTokenizer;
    
    public class Main {
    	
    //	14503
    	
    	static int[] moveN = {-1, 0, 1, 0};
    	static int[] moveM = {0, 1, 0, -1};
    	static int cnt = 1;
    	static int[][] map;
    	public static void main(String[] args) throws IOException {
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		StringTokenizer st = new StringTokenizer(br.readLine());
    		int N, M, r, c, d;
    		
    		N = Integer.parseInt(st.nextToken());
    		M = Integer.parseInt(st.nextToken());
    		st = new StringTokenizer(br.readLine());
    		r = Integer.parseInt(st.nextToken());
    		c = Integer.parseInt(st.nextToken());
    		d = Integer.parseInt(st.nextToken());
    		
    		map = new int[N][M];
    		
    		for(int i = 0; i < N; i++) {
    			String[] s = br.readLine().split(" ");
    			for(int j = 0; j < M; j++) {
    				map[i][j] = Integer.parseInt(s[j]);
    			}
    		}
    		dfs(r, c, d, N, M);
    		System.out.println(cnt);
    		
    	}
    	
    	public static  void dfs(int r, int c, int d, int N, int M) throws IOException {
    		
    		map[r][c] = -1;
    		
    		for(int i = 0; i < 4; i++) {
    			
    			d = (d + 3) % 4;
    			int nextX = r + moveN[d];
    			int nextY = c + moveM[d];
    			
    			if(nextX >= 0 && nextY >= 0 && nextX < N && nextY < M && map[nextX][nextY] == 0) {
    				cnt++;
    				dfs(nextX, nextY, d, N, M);
    				
    				return;
    			}
    			
    		}
    		
    		int back = (d + 2) % 4;
    		int backX = r + moveN[back];
    		int backY = c + moveM[back];
    		
    		if(backX >= 0 && backY >= 0 && backX < N && backY < M && map[backX][backY] != 1) {
    			dfs(backX, backY, d, N, M); 
    		}
    		
    	}
    	
    }

    - 처음부터 dfs 방식을 떠올리지 못했는데 그래프 탐색 방법에 대해서 다시 한번 짚어야 겠다는 생각을 하였다. 기존의 dfs탐색에서 방향을 가지고 청소할 곳이나 사방이 벽일 때 후진하는 로직이 주요했다. mod 연산자를 좀 더 활용하는 방법으로 로직을 설계하도록 하는 습관을 길러야겠다. 갈길이 멀다,,

    5. ABCDE(13023) https://www.acmicpc.net/problem/13023

    👉 소스코드

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.util.ArrayDeque;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Deque;
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.StringTokenizer;
    
    public class Main {
    	
    	static int N, M, cnt;
    	static ArrayList<ArrayList<Integer>> map = new ArrayList<>();
    	static boolean[] visited;
    	static boolean flag = false;
    	
    	public static void main(String[] args) throws IOException {
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    		StringTokenizer st = new StringTokenizer(br.readLine());
    		
    		N = Integer.parseInt(st.nextToken());
    		M = Integer.parseInt(st.nextToken());
    		
    		for(int i = 0; i < N; i++) {
    			map.add(new ArrayList<Integer>());
    		}
    		
    		visited = new boolean[N];
    		
    		for(int i = 0; i < M; i++) {
    			st = new StringTokenizer(br.readLine());
    			int a = Integer.parseInt(st.nextToken());
    			int b = Integer.parseInt(st.nextToken());
    			map.get(a).add(b);
    			map.get(b).add(a);
    		}
    		
    		for(int i = 0; i < M; i++) {
    			if(cnt == 0) {
    				dfs(i, 1);
    			}
    			if(flag) break;
    		}
    		bw.write((flag ? 1 : 0) + "\n");
    		bw.flush();
    		br.close();
    	}
    	
    	public static void dfs(int x, int y) {
    		if(y == 5) {
    			flag = true;
    			return;
    		}
    		
    		visited[x] = true;
    		
    		for(int i : map.get(x)) {
    			if(!visited[i]) {
    				dfs(i, y+1);
    			}
    		}
    		if(flag) return;
    		visited[x] = false;
    		
    	}
    	
    	
    }

    - 일반적인 dfs 문제지만 주의사항이 몇가지 있다. 

    1. 친구 관계를 오인하는 경우가 있음 - > 인접 리스트를 생성할 때 A와 B가 친구고 B와 C가 친구이면 A와 C도 친구가 될 수 있다고 생각하여 두 인접 리스트에도 추가하는 경우인데, 주어진 입력 정보는 친구 즉, 간선 정보 이기때문에 예시를 든 것 같이 친구 관계는 중복 될 수 없음을 인지하고 풀이를 했어야 한다.
    2. 노드가 일직선상에 있는지 판단을 잘못하는 경우 
    3. 그리고 모두 방문된 노드에 대한 true는 false로 변경할 것

    6. 토마토(7576) https://www.acmicpc.net/problem/13023

    👉 소스코드

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.StringTokenizer;
    
    public class Main {
    	
    	static int M, N, count, notTo;
    	static int[][] map;
    	static boolean[][] visited;
    	static int[] moveN = {0, 0, -1, 1}, moveM = {-1, 1, 0, 0};
    	static Queue<Tomato> okTo = new LinkedList<Tomato>();
    	
    	public static void main(String[] args) throws IOException {
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		StringTokenizer st = new StringTokenizer(br.readLine());
    		
    		M = Integer.parseInt(st.nextToken());
    		N = Integer.parseInt(st.nextToken());
    
    		map = new int[N][M];
    		visited = new boolean[N][M];
    		
    		for(int i = 0; i < N; i++) {
    			String[] s = br.readLine().split(" ");
    			for(int j = 0; j < M; j++) {
    				map[i][j] = Integer.parseInt(s[j]);
    				if(map[i][j] == 0) notTo++;
    				else if(map[i][j] == 1) okTo.offer(new Tomato(i, j));
    			}
    		}
    		bfs();
    		System.out.println(notTo == 0 ? count : -1);
    		
    	}
    	
    	public static void bfs() {
    		while(notTo > 0 && !okTo.isEmpty()) {
    			int size = okTo.size();
    			
    			for(int i = 0; i < size; i++) {
    				Tomato t = okTo.poll();
    				int curN = t.x;
    				int curM = t.y;
    				
    				for(int j = 0; j < 4; j++) {
    					
    					int nextN = curN + moveN[j];
    					int nextM = curM + moveM[j];
    					
    					if(nextN < 0 || nextM < 0 || nextN >= N || nextM >= M) continue;
    					
    					if(map[nextN][nextM] != 0) continue;
    					
    					notTo--;
    					okTo.offer(new Tomato(nextN, nextM));
    					map[nextN][nextM] = 1;
    				}
    			}
    			count++;
    		}
    	}
    	
    	static class Tomato {
    		int x;
    		int y;
    		
    		public Tomato (int x, int y) {
    			this.x = x;
    			this.y = y;
    		}
    	}
    }

    -토마토(7569)와 동일한 문제 처음에 입력받을 때 당시 익은 토마토의 위치는 큐에다가 집어넣고 익지 않은 토마토는 개수만 세어준 후 익은 토마토의 개수만큼 반복문을 돌려주면서 상하좌우 익을 수 있는 토마토가 있는지 체크해가면서 counting 하면 되는 문제

    7. 숨바꼭질 3(13549) https://www.acmicpc.net/problem/13549

    👉 소스코드

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.util.ArrayDeque;
    import java.util.Arrays;
    import java.util.Deque;
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.StringTokenizer;
    
    public class Main {
    	
    	static int subin, sister;
    	
    	public static void main(String[] args) throws IOException {
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		StringTokenizer st = new StringTokenizer(br.readLine());
    		
    		subin = Integer.parseInt(st.nextToken());
    		sister = Integer.parseInt(st.nextToken());
    		
    		System.out.println(oneZeroBfs());
    		br.close();
    		
    	}
    	
    	public static int oneZeroBfs() {
    		Deque<Integer> q = new ArrayDeque<Integer>();
    		q.offer(subin);
    		int[] visited = new int[100001];
    		Arrays.fill(visited, Integer.MAX_VALUE);
    		
    		visited[subin] = 0;
    		
    		while(!q.isEmpty()) {
    			int cur = q.poll();
    			
    			if(cur == sister) return visited[sister];
    			
    			if(cur * 2 <= 100000 && visited[cur * 2] > visited[cur]) {
    				visited[cur * 2] = visited[cur];
    				q.offerFirst(cur * 2);;
    			}
    			if(cur + 1 <= 100000 && visited[cur + 1]  > visited[cur] + 1) {
    				visited[cur + 1] = visited[cur] + 1;
    				q.offerLast(cur + 1);
    			}
    			if(cur - 1 >= 0 && visited[cur - 1]  > visited[cur] + 1) {
    				visited[cur - 1] = visited[cur] + 1;
    				q.offerLast(cur - 1);
    			}
    		}
    		return 0;
    	}
    }

    - 순간이동을 하는 경우 (X*2) 때문에 가선의 가중치가 달라진다. 그러므로 일반적인 bfs가 아닌 0-1 bfs로 풀이 진행했다. 현재 수빈이가 있는 자리 + 1 (시간을 소비하여 행위를 하는 경우)이  현재 수빈이가 있는 자리 + 가중치 보다 크다면 해당 행위를 진행하고, 배열에 표시되어 있는 자리에 값을 갱신하여 주면 된다. (아래는 다익스트라 코드로 풀이한 방법)

    public static int dijkstra() {
    		PriorityQueue<Loc> q = new PriorityQueue<Loc>();
    		q.offer(new Loc(subin, 0));
    		boolean[] visited = new boolean[maxNum + 1];
    		visited[subin] = true;
    		
    		while(!q.isEmpty()) {
    			Loc l = q.poll();
    			visited[l.start] = true;
    			
    			if(l.start == sister) return l.count;
    			
    			if(l.start * 2 <= maxNum && !visited[l.start * 2]) {
    				q.offer(new Loc(l.start * 2, l.count));
    			}
    			
    			if(l.start + 1 <= maxNum && !visited[l.start + 1]) {
    				q.offer(new Loc(l.start + 1, l.count + 1));
    			}
    			if(l.start - 1 >= 0 && !visited[l.start - 1]) {
    				q.offer(new Loc(l.start - 1, l.count + 1));
    			}
    			
    		}
    		
    		return 0;
    	}
    	
    	 static class Loc implements Comparable<Loc>{
    		int start, count;
    		
    		public Loc(int start, int count) {
    			this.start = start;
    			this.count = count;
    		}
    		
    		@Override
    		public int compareTo(Loc l) {
    			return this.count - l.count;
    		}
    	}
    }