• toc {:toc}

문제

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

  • 1부터 N까지 자연수 중에서 M개를 고른 수열
  • 같은 수를 여러 번 골라도 된다.
  • 고른 수열은 비내림차순이어야 한다.
    • 길이가 K인 수열 A가 A ≤ A ≤ … ≤ A ≤ A를 만족하면, 비내림차순이라고 한다. (이전 수보다 크거나 같아야 한다.)

입력

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

출력

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

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

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

풀이

현재 추가되어야 하는 수가 이전 수보다 작다면 pass 한다.

이외에는 백트래킹을 구현한다.

#include <bits/stdc++.h>
using namespace std;
 
int n, m;
int num[10];
int is_used[10][10];
 
void func(int cur, int fixed){
    if(cur == m){
        for(int i=0; i<m; i++){
            cout << num[i] << ' ';
        }
        cout << '\n';
        return;
    }
    for(int i = 1; i<=n; i++){
        if(is_used[fixed][i]) continue; // 사용되지 않았다면
        if(cur!=0 && num[cur-1] > i) continue;
        is_used[fixed][i]=1;
        num[cur] = i; 
        func(cur+1, fixed+1);
        is_used[fixed][i]=0;
    }
}
 
int main(){
    ios::sync_with_stdio();
    cin.tie(0);
    cin >> n >> m;
    func(0, 0);
    return 0;
}

정답코드

시작지점을 재설정해주면서 중복이 이루어진다.

그리고 arr[k-1]로 설정하면서 이전 수보다 더 작지 않도록 설정한다.

// Authored by : BaaaaaaaaaaarkingDog
// Co-authored by : -
// http://boj.kr/a237cd7949004a76aa9ac3cf1b13c03c
#include <bits/stdc++.h>
using namespace std;
 
int n, m;
int arr[10];
 
void func(int k){ // 현재 k개까지 수를 택했음.
  if(k == m){ // m개를 모두 택했으면
    for(int i = 0; i < m; i++)
      cout << arr[i] << ' '; // arr에 기록해둔 수를 출력
    cout << '\n';
    return;
  }
  int st = 1; // 시작지점, k = 0일 때에는 st = 1
  if(k != 0) st = arr[k-1]; // k != 0일 경우 st = arr[k-1]
  for(int i = st; i <= n; i++){
    arr[k] = i; // k번째 수를 i로 정함
    func(k+1); // 다음 수를 정하러 한 단계 더 들어감
  }
}
 
int main(void){
  ios::sync_with_stdio(0);
  cin.tie(0);
  cin >> n >> m;
  func(0);
}