- Today
- Yesterday
- Total
메이쁘
(JAVA) 백준 9938번 : 방 청소 본문
https://www.acmicpc.net/problem/9938
9938번: 방 청소
문제 은기는 술병 N개(1부터 N까지 번호가 매겨져 있다)와 서랍 L개(1부터 L까지 번호가 매겨져 있다)를 가지고 있다. 술병은 은기의 방 바닥에 흩어져 있고, 어린이날을 맞이해 방 청소를 하려고 �
www.acmicpc.net
너무 이해가 되지 않아
풀이를 참고한 문제.
난이도는 좀 높다.
이게 생각을 살짝 바꾸면 해결할 수 있는데 그게 어렵다.
그리고 문제에서

형광칠한 부분이 조금 이해가 안됬었다.
- 만약 Union - Find 알고리즘을 사용해야 한다면 술을 다른 서랍으로 이동시키기 위해 parent를 어떻게 설정할 건지
- 술을 서랍에 넣었을 때를 체크해두는 방법
이렇게 두 가지를 해결못해 풀이 참고를 했었다.
핵심은
- 서랍에 술을 넣었는지 여부를 파악하기 위해 boolean 배열 생성해서 관리한다.
- 술을 해당 서랍에 넣을 때, parent는 넣지 않은 다른 서랍 번호를 술을 넣은 서람의 parent로 설정한다.
즉, A 서랍에 술을 넣으면 parent[A] = B 가 되고, B 서랍에 술을 넣으면 parent[B] = A 가 된다.
*** 아래에도 적혀있지만, 술을 넣은 서랍의 parent를 적용시키는 이유는 그 서랍에 새로운 술을 넣으려고하면 이전 술을 옮겨야하니까 옮길 다음 서랍을 파악해두기 위함이다.
- 따라서, 조건 3과 4를 위해 술을 옮기는 과정은 Find()로 해결할 수 있다.
Find()로 점핑하다보면 결국 비어있는 노드를 발견할 수 있다.
A에서 발견 못하면 B에서도 동일하게 진행한다.
- 조건 1, 2, 3, 4 모두 술을 넣은 다음 union을 진행한다.
그래야 해당 서랍에 새로운 술이 들어왔을 때 이전 술을 점핑시킬 다른 서랍을 알 수 있다.
*** 중요한 점은 술을 다른 서랍으로 옮기더라도 결국에 새로운 술이 처음 서랍에 들어가기 때문에 한 번 서랍에 술을 넣으면 절대 사라지지 않는 것과 같다.
위 핵심이 곧 매커니즘이기 때문에
별도 매커니즘은 작성하지 않고
바로 소스코드를 첨부하겠습니다.
감사합니다!
소스코드
package disjointSet; | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.util.ArrayList; | |
import java.util.LinkedList; | |
import java.util.Queue; | |
import java.util.StringTokenizer; | |
// 여행 가자 | |
// Disjoint - Set ? | |
public class p1976 { | |
static int[][] map; | |
static ArrayList<Integer>[] graph; | |
static ArrayList<Integer> route; | |
public static void main(String args[]) throws IOException { | |
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); | |
StringTokenizer st = new StringTokenizer(br.readLine()); | |
int n = Integer.parseInt(st.nextToken()); | |
int m = Integer.parseInt(br.readLine()); | |
route = new ArrayList<Integer>(); | |
graph = new ArrayList[n + 1]; | |
for(int i = 1; i <= n; i++) { | |
graph[i] = new ArrayList<Integer>(); | |
} | |
// Input 넣기 | |
for(int i = 1; i <= n; i++) { | |
st = new StringTokenizer(br.readLine()); | |
for(int j = 1; j <= n; j++) { | |
int num = Integer.parseInt(st.nextToken()); | |
if(num == 1) { | |
graph[i].add(j); | |
} | |
} | |
} | |
st = new StringTokenizer(br.readLine()); | |
while(st.hasMoreTokens()) { | |
int dest = Integer.parseInt(st.nextToken()); | |
route.add(dest); | |
} | |
String print = possibleRoute(n, route.get(0)) ? "YES" : "NO"; | |
System.out.println(print); | |
} | |
static boolean possibleRoute(int n, int start) { | |
boolean[] visited = new boolean[n + 1]; | |
Queue<Integer> q = new LinkedList<Integer>(); | |
q.offer(start); | |
while(!q.isEmpty()) { | |
int ele = q.poll(); | |
if(visited[ele]) { | |
continue; | |
} | |
visited[ele] = true; | |
for(int i = 0; i < graph[ele].size(); i++) { | |
int next = graph[ele].get(i); | |
q.offer(next); | |
} | |
} | |
// 경로에 한 번이라도 방문한 적이 있는지 파악하기 | |
// 중복 경로가 가능하고, 이전 길로도 되돌아갈 수 있어서 한 번이라도 방문했으면 어떤 순서건 간에 방문할 수 있다. | |
for(int dest : route) { | |
if(visited[dest]) { | |
continue; | |
} | |
return false; | |
} | |
return true; | |
} | |
} |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.util.StringTokenizer; | |
// 방 청소 | |
// Union - Find | |
public class p9938 { | |
static boolean[] checked; | |
static int[] drawerParent; | |
static StringBuilder sb; | |
public static void main(String args[]) throws NumberFormatException, IOException { | |
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); | |
StringTokenizer st = new StringTokenizer(br.readLine()); | |
int n = Integer.parseInt(st.nextToken()); | |
int l = Integer.parseInt(st.nextToken()); | |
checked = new boolean[l + 1]; // 1 ~ L | |
drawerParent = new int[l + 1]; | |
sb = new StringBuilder(); | |
// parent 노드 초기화 | |
for(int i = 1; i <= l; i++) { | |
drawerParent[i] = i; | |
} | |
for(int i = 1; i <= n; i++) { | |
st = new StringTokenizer(br.readLine()); | |
int a = Integer.parseInt(st.nextToken()); | |
int b = Integer.parseInt(st.nextToken()); | |
if(!checked[a]) { // 1번 조건 : 서랍 a가 비어있는 경우 | |
checked[a] = true; | |
union(a, b); | |
} | |
else if(!checked[b]) { // 2번 조건 : 서랍 b가 비어있는 경우 | |
checked[b] = true; | |
union(b, a); | |
} | |
else if(!checked[find(a)]) { // 3번 조건 : 서랍 a에 술병이 있는 경우 | |
checked[find(a)] = true; | |
union(a, b); | |
} | |
else if(!checked[find(b)]) { // 4번 조건 : 서랍 b에 술병이 있는 경우 | |
checked[find(b)] = true; | |
union(b, a); | |
} | |
else { | |
sb.append("SMECE").append("\n"); | |
} | |
} | |
System.out.println(sb.toString()); | |
} | |
static void union(int a, int b) { | |
a = find(a); | |
b = find(b); | |
drawerParent[a] = b; | |
sb.append("LADICA").append("\n"); | |
} | |
static int find(int index) { | |
if(drawerParent[index] == index) { | |
return index; | |
} | |
return drawerParent[index] = find(drawerParent[index]); | |
} | |
} |
'Algorithm > Baekjoon' 카테고리의 다른 글
(JAVA) 백준 6588번 : 골드바흐의 추측 (0) | 2020.06.01 |
---|---|
(JAVA) 백준 1976번 : 여행 가자 (0) | 2020.06.01 |
(JAVA) 백준 10774번 : 저지 (0) | 2020.05.31 |
(JAVA) 백준 4195번 : 친구 네트워크 (0) | 2020.05.31 |
(JAVA) 백준 10775번 : 공항 (0) | 2020.05.29 |