코딩테스트/백준

[백준 15652] N과 M(4) (Java) - DFS, 백트래킹

imachill7guy 2025. 4. 29. 22:06

https://www.acmicpc.net/problem/15652

N과 M (4)

문제

자연수 N과 M이 주어졌을 때, 아래 조건을 만족하는 길이가 M인 수열을 모두 구하는 프로그램을 작성하시오.

  • 1부터 N까지 자연수 중에서 M개를 고른 수열
  • 같은 수를 여러 번 골라도 된다.
  • 고른 수열은 비내림차순이어야 한다.
    • 길이가 K인 수열 A가 A1 ≤ A2 ≤ ... ≤ AK-1 ≤ AK를 만족하면, 비내림차순이라고 한다.

입력

첫째 줄에 자연수 N과 M이 주어진다. (1 ≤ M ≤ N ≤ 8)

출력

한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다.

수열은 사전 순으로 증가하는 순서로 출력해야 한다.

예제 입력 1 복사

3 1

예제 출력 1 복사

1
2
3

예제 입력 2 복사

4 2

예제 출력 2 복사

1 1
1 2
1 3
1 4
2 2
2 3
2 4
3 3
3 4
4 4

예제 입력 3 복사

3 3

예제 출력 3 복사

1 1 1
1 1 2
1 1 3
1 2 2
1 2 3
1 3 3
2 2 2
2 2 3
2 3 3
3 3 3

풀이

import java.io.*;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    static int N,M;
    static int[] num;
    static ArrayList<Integer> sequence = new ArrayList<>();
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    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());

        num = new int[N+1]; // 1부터 시작
        for (int i=1; i<N+1; i++){
            num[i] = i;
        }
        DFS(1,0);
        bw.flush();
        bw.close();
    }
    private static void DFS(int start, int depth)throws IOException{
        if (depth == M){
            for (int seq : sequence){
                bw.write(seq + " ");
            }
            bw.write("\n");
            return;
        }

        for (int i=start; i<N+1; i++){
            sequence.add(num[i]);
            DFS(i, depth+1);
            sequence.remove(sequence.size()-1); // 백트래킹
        }

    }
}

 

  • DFS, 백트래킹을 활용한 문제
  • 1 ~ N까지의 자연수 중 M개를 고른 수열을 고르되, 아래 조건을 만족해야한다.
    • 같은수를 여러번 골라도 된다.
    • 오름차순 정렬
    • 중복되는 수열을 여러번 출력해선 안된다.
  • 여기서 관건은, 같은 수를 여러번 골라도 되나, 중복되는 수열을 출력하면 안된다.
  • 따라서 start값을 받아서 num배열에서 몇 번째 index 부터 쓸 것인지 정하면된다.
for (int i=start; i<N+1; i++){
            sequence.add(num[i]);
            DFS(i, depth+1);
            sequence.remove(sequence.size()-1); // 백트래킹
        }
  • DFS 재귀호출 부분에서 for문을 그냥 i=1 ~ N까지 순회하게 되면 중복된 수열을 출력하게 된다.
  • 예를 들어서 1 2와 2 1 은 같은 수열로 취급해버리기 때문이다.
  • 따라서 어차피 오름차순 정렬이기 때문에 현재 i값을 가지고 재귀호출 파라미터에 start값을 i로 주면 중복수열을 방지할 수 있다. 

 

 

해당문제는 백준 15650 N과 M(2) 문제와 유사하다

https://why-so-chill.tistory.com/70