문제
https://www.acmicpc.net/problem/15663
들어가며
이 문제는 N과 M(5)에서 수열에 중복된 숫자가 들어갈 수 있는 차이가 있다.
참고) N과 M(5) - https://namamim.tistory.com/60
따라서 위에서 사용한 코드를 기반으로 충분히 문제를 풀 수 있다.
이걸 해결하는데 크게 두 가지의 방식있다.
방식 1 - 순열을 다 만들고 중복 거르기
코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class 백준15664_N과M9 {
static int n, m;
static int[] nums;
static int[] output;
static boolean[] visited;
static Set<String> set = new LinkedHashSet<>();
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
nums = Arrays.stream(br.readLine().split(" "))
.mapToInt(Integer::parseInt)
.toArray();
visited = new boolean[n];
output = new int[m];
Arrays.sort(nums);
search(0);
StringBuilder result = new StringBuilder();
for (var i : set){
result.append(i).append("\n");
}
System.out.println(result);
}
static void search(int depth){
if (depth >= m){
StringBuilder temp = new StringBuilder();
for (int i = 0; i < m; i++){
temp.append(output[i]).append(" ");
}
set.add(temp.toString());
return;
}
for (int i = 0; i <n; i++){
if (!visited[i]){
visited[i] = true;
output[depth] = nums[i];
search(depth+1);
visited[i] = false;
}
}
}
}
풀이
아주 단순히 생각하면 모든 순열을 만들고 중복만 거르면 된다.
여기서 흔히 사용하는 것이 Set인데, Set은 중복은 거를 수 있으나 순서가 보장되지 않는다.
문제는 사전 정렬을 원하기 때문에 순서가 유지되어야 한다.
그럴 때 사용할 수 있는 것이 LinkedHashSet 이다.
입력 순서를 유지하기 때문에 성능은 좀 HashSet보다 안좋다.
하지만, 찬물 뜨거운 물 거를 때가 아니므로 사용하면 된다.
방식 2 - 순열을 만들 때 미리 거르기
코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class 백준15664_N과M9 {
static int n, m;
static int[] nums;
static int[] output;
static boolean[] visited;
static StringBuilder result = new StringBuilder();
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
nums = Arrays.stream(br.readLine().split(" "))
.mapToInt(Integer::parseInt)
.toArray();
Arrays.sort(nums);
output = new int[m];
visited = new boolean[n];
search(0);
System.out.println(result);
}
static void search(int depth) {
if (depth == m) {
for (int i = 0; i < m; i++) {
result.append(output[i]).append(" ");
}
result.append("\n");
return;
}
int lastUsed = -1;
for (int i = 0; i < n; i++) {
if (visited[i] || nums[i] == lastUsed) {
continue;
}
visited[i] = true;
output[depth] = nums[i];
lastUsed = nums[i];
search(depth + 1);
visited[i] = false;
}
}
}
풀이
int lastUsed = -1;
for (int i = 0; i < n; i++) {
if (visited[i] || nums[i] == lastUsed) {
continue;
}
visited[i] = true;
output[depth] = nums[i];
lastUsed = nums[i];
search(depth + 1);
visited[i] = false;
}
이전과 다르게 lastUsed가 추가 됐다.
이전값을 저장한 것이다.
이미 수열을 사전으로 정렬했기 때문에, 같은 숫자들은 모여있다.
예시) 1,2,2,3,3,4
그렇기에 중복 처리는 이전 값이 지금이랑 같은 지만 파악하면 끝이난다.
'알고리즘 문제 풀이 > 백준' 카테고리의 다른 글
[백준]1629 - 곱셈 문제 풀이(Java,자바) (0) | 2025.02.14 |
---|---|
[백준]11053-가장 긴 증가하는 부분 수열 문제 풀이(Java,자바) (3) | 2025.02.08 |
[백준]15654-N과M(5) 문제 풀이(Java,자바) (0) | 2025.02.07 |
[백준]1012-유기농 배추 문제 풀이(Java,자바) (0) | 2025.02.06 |
[백준]7569- 토마토 문제 풀이(Java,자바) (0) | 2025.02.05 |