안녕하세요. 이번에는 백준 15650. N과 M (2) 문제를 풀어보겠습니다.
https://www.acmicpc.net/problem/15650
1부터 N까지 자연수 중에서 중복 없이 M개를 고르고, 고른 수열은 오름차순이어야 합니다.
중복 없이 M개를 고르기 위해서는 이전에 탐색했는지 여부를 저장해주어야 합니다. dfs로 1부터 N까지 모든 수를 탐색하되, visited 배열을 이용해서 이전 탐색 여부를 저장해주면 됩니다. 탐색한 값은 answer배열에 저장해줍니다.
이전에 풀었던 N과 M (1) 문제에서는 "1 2"와 "2 1"을 다른 경우로 체크했습니다. 하지만 이번 문제는 고른 수열이 오름차순이므로, "1 2"와 "2 1"이 모두 "1 2"로 똑같습니다. 해당 요구사항은 dfs함수 속 for문의 index를 조절하면 됩니다.
두 가지 요구사항을 반영한 핵심 코드는 다음과 같습니다.
boolean[] visited = new boolean[n+1];
int[] answer = new int [m];
//n = 탐색해야 할 자연수(1부터 n까지)
//m = 골라야 하는 숫자의 갯수
//idx = 현재까지 dfs함수를 탐색하면서 골라둔 숫자의 갯수
//at = 탐색을 시작해야 하는 숫자
dfs(int n, int m, int idx, int at) {
//dfs 탐색을 멈추는 로직
if(idx가 m과 같다면) { //dfs를 탐색하면서 고른 숫자 갯수가 m이라면
//answer 배열을 출력한 후 dfs 탐색을 멈춘다
return;
}
//dfs 탐색 로직
for(int i = at; i <= n; i++) { //at부터 n까지 for문을 수행
if(visited[i] == false) { //아직 i값을 탐색하지 않았다면
visited[i] = true; //i를 탐색한다
answer[idx] = i; //answer배열의 idx번째 값을 i로 저장
dfs(n, m, idx +1, i+1); //고른 숫자의 총 개수가 1 증가했으니까, idx를 1 증가시키고, 현재 탐색한 i값보다 1 증가시킨 값을 at으로 바꿔서 dfs를 수행한다
visited[i] = false; //dfs가 모든 경우의 수를 탐색해야하므로 해당 재귀함수가 완료된 후 탐색여부를 false로 바꾼다
}
}
}
import java.io.*;
import java.util.*;
public class Main {
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(st.nextToken());
visited = new boolean[n+1];
answer = new int[m];
sb = new StringBuilder();
dfs(n, m, 0, 1);
System.out.println(sb.toString());
}
private static boolean[] visited;
private static int[] answer;
private static StringBuilder sb;
private static void dfs(int n, int m, int idx, int at) {
if(idx == m) {
for(int num : answer) {
sb.append(num + " ");
}
sb.append("\n");
return;
}
for(int i = at; i <= n; i++) {
if(visited[i] == false) {
visited[i] = true;
answer[idx] = i;
dfs(n, m, idx + 1, i + 1);
visited[i] = false;
}
}
}
}
[참고한 곳]
https://st-lab.tistory.com/115
https://velog.io/@fantastik/31