https://www.acmicpc.net/problem/2668
2668번: 숫자고르기
세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절
www.acmicpc.net
풀이
BFS를 응용하여, 첫째 줄의 숫자를 고르면 그 숫자에 둘째 줄에 있는 숫자를 큐에 집어넣는 과정을 반복해서 최종적으로 각 숫자들이 2번씩 포함되는지를 체크하였다.
한 사이클을 찾아내면, 첫째 줄과 둘째 줄이 같은 숫자들을 추가하여 크기를 구하여 최대 크기의 사이클을 계속해서 업데이트하는 로직을 생각했다.
하지만 사이클이 여러 개 있을 수 있고, 각 숫자는 오직 1개 이하의 사이클에만 포함되므로, 따로 ArrayList<ArrayList<Integer>>에 각 사이클을 저장할 필요 없이 boolean[] 배열을 사용하여 문제를 풀었다.
static int n;
static int[] numbers; // numbers[i] = i번째 숫자의 둘째 줄 숫자
static boolean[] isCycle; // i가 사이클에 포함되어 있으면 true
로직
1. numbers를 입력받는다. 이 때 첫째 줄과 둘째 줄의 숫자가 같다면 isCycle[i] = true로 변경한다.
2. 1부터 n까지 각 숫자를 시작점으로 하는 BFS를 수행한다. 이 때 isCycle[i]가 true라면 BFS를 수행하지 않는다.
3. BFS는 큐와 방문배열, Map을 사용한다.
- Map에는 (숫자, 그 숫자가 포함된 횟수)를 저장한다.
- 큐에 시작점의 숫자를 넣는다.
- 큐에서 숫자를 뽑으면 그 숫자에 둘째 줄에 있는 숫자를 큐에 집어넣는다. 이 때 뽑은 숫자와 그 숫자의 둘째 줄 숫자에 대해 Map을 업데이트한다.
- BFS가 종료되고 Map에 각 숫자가 2번 포함되었는지 확인한다. 2번 포함되지 않은 숫자가 있다면 바로 함수를 종료하고, 통과되면 사이클에 포함된 모든 숫자의 isCycle[i] = true로 변경한다.
4. 사이클을 생성한 숫자들을 ArrayList<Integer> answer에 저장한다.
5. answer의 사이즈와 숫자들을 차례대로 출력한다. 이미 1부터 순서대로 저장되어있으므로 answer을 따로 정렬할 필요 없다.
코드
import java.io.*;
import java.util.*;
public class Main {
static int n;
static int[] numbers;
static boolean[] isCycle;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
n = Integer.parseInt(br.readLine());
numbers = new int[n+1];
isCycle = new boolean[n+1];
for (int i = 1; i <= n; i++) {
numbers[i] = Integer.parseInt(br.readLine());
if (i == numbers[i]) {
isCycle[i] = true;
}
}
for (int i = 1; i <= n; i++) {
if (isCycle[i]) continue;
bfs(i);
}
// 사이클에 저장되어있는 숫자들을 answer에 저장
ArrayList<Integer> answer = new ArrayList<>();
for (int i = 1; i <= n; i++) {
if (isCycle[i]) {
answer.add(i);
}
}
// 순서대로 저장되어 있으니 그대로 출력
sb.append(answer.size() + "\n");
for (int num: answer) {
sb.append(num + "\n");
}
System.out.println(sb);
}
static void bfs(int start) {
Queue<Integer> q = new ArrayDeque<>();
boolean[] visited = new boolean[n+1];
Map<Integer, Integer> numCnt = new HashMap<>();
q.add(start);
visited[start] = true;
while (!q.isEmpty()) {
int cur = q.poll();
int num = numbers[cur];
numCnt.put(cur, numCnt.getOrDefault(cur, 0)+1);
numCnt.put(num, numCnt.getOrDefault(num, 0)+1);
if (visited[num]) {
break;
}
q.add(num);
visited[num] = true;
}
for (int num: numCnt.keySet()) {
int cnt = numCnt.get(num);
if (cnt != 2) return;
}
for (int num: numCnt.keySet()) {
isCycle[num] = true;
}
}
}
'Algorithm 문제 풀이 > 백준' 카테고리의 다른 글
[백준] 16918번 : 봄버맨 - 자바[Java] (1) | 2024.01.08 |
---|---|
[백준] 1283번 : 단축키 지정 - 자바[Java] (0) | 2024.01.07 |
[백준] 11286번 : 절댓값 힙 - 자바[Java] (0) | 2023.10.16 |
[백준] 2800번 : 괄호 제거 - 자바[Java] (1) | 2023.10.16 |
[백준] 2503번 : 숫자 야구 - 자바[Java] (0) | 2023.10.13 |