본문으로 바로가기

[DFS] N과 M

category Algorithm/BOJ 문제풀이 2018. 11. 18. 00:04
N과M

N과 M

백트래킹(Backtracking)

  • 한정 조건을 가진 문제를 풀려는 전략
  • 어떤 노드의 유망성 점검 후, 유망하지 않으면 그 노드의 부모노드로 되돌아가서 다른 자손 노드를 검색함

 

15649번 N과 M(1)

 

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


 

문제

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

  • 1부터 N까지 자연수 중에서 중복 없이 M개를 고른 수열

 

입력

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

 

출력

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

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

 

예제 입력

4 2

 

예제 출력

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

 

해결방법

백트래킹으로 DFS 를 수행하는 문제이다.

dfs + 조합의 문제는 아직 익숙하지 않아서 중간에 소스코드를 참조했다.

또한 시간초과가 나왔는데 cin → scanf() , cout →printf() 로 바꾸니 해결되었다.

백트래킹 문제는 더 풀어보면서 연습해야겠다.

 

소스코드

#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 8
using namespace std;

int n,m;
int arr[MAX];
int ind[MAX];
bool check[MAX];

void dfs(int cnt){
    if(cnt == m){
        for(int i=0; i<m; i++){
            printf("%d ",arr[ind[i]]);
        }
        printf("\n");
    }
    
    // DFS
    for(int i=0; i<n; i++){
        if(!check[i]){
            check[i] = true;
            ind[cnt] = i;
            dfs(cnt+1);
            check[i] = false;
        }
    }
}

int main(int argc, const char * argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    scanf("%d %d",&n,&m);
    for(int i=0; i<n; i++){
        arr[i] = i+1;
    }
    
    dfs(0);
}

 




 

15650번 N과 M(2)

 

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


 

문제

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

  • 1부터 N까지 자연수 중에서 중복 없이 M개를 고른 수열
  • 고른 수열은 오름차순이어야 한다.

 

입력

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

 

출력

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

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

 

예제 입력

4 2

 

예제 출력

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

 

해결방법

백트래킹으로 DFS 를 수행하는 문제이다.

하지만 이번에는 결과가 오름차순으로 출력되어야한다.

이는 재귀 함수를 호출할 때, 현재 인덱스를 전송하여 그 인덱스부터 반복문을 돌리며 다시 재귀함수를 호출하는 방법으로 구현하였다.

 

소스코드

#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 8
using namespace std;

int n,m;
int arr[MAX];
int ind[MAX];
bool check[MAX];

void dfs(int index, int cnt){
    if(cnt == m){
        for(int i=0; i<m; i++){
            printf("%d ",arr[ind[i]]);
        }
        printf("\n");
    }
    
    // DFS
    for(int i=index; i<n; i++){
        if(!check[i]){
            check[i] = true;
            ind[cnt] = i;
            dfs(i,cnt+1);
            check[i] = false;
        }
    }
}

int main(int argc, const char * argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    scanf("%d %d",&n,&m);
    for(int i=0; i<n; i++){
        arr[i] = i+1;
    }
    
    dfs(0,0);
}

 




 

15651번 N과 M(3)

 

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


 

문제

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

  • 1부터 N까지 자연수 중에서 M개를 고른 수열
  • 같은 수를 여러 번 골라도 된다.

 

입력

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

 

출력

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

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

 

예제 입력

4 2

 

예제 출력

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

 

해결방법

check배열을 지운 뒤 1번과 동일하게 진행!

 

소스코드

#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 8
using namespace std;

int n,m;
int arr[MAX];
int ind[MAX];

void dfs(int cnt){
    if(cnt == m){
        for(int i=0; i<m; i++){
            printf("%d ",arr[ind[i]]);
        }
        printf("\n");
        return;
    }
    
    // DFS
    for(int i=0; i<n; i++){
        ind[cnt] = i;
        dfs(cnt+1);
    }
}

int main(int argc, const char * argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    scanf("%d %d",&n,&m);
    for(int i=0; i<n; i++){
        arr[i] = i+1;
    }
    
    dfs(0);
}

 




 

15652번 N과 M(4)

 

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


 

문제

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

  • 1부터 N까지 자연수 중에서 M개를 고른 수열

  • 같은 수를 여러 번 골라도 된다.

  • 고른 수열은 비내림차순이어야 한다.

    • 길이가 K인 수열 A가 A1 ≤ A2 ≤ ... ≤ AK-1 ≤ AK를 만족하면, 비내림차순이라고 한다.

 

입력

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

 

출력

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

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

 

예제 입력

4 2

 

예제 출력

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

 

해결방법

check배열을 지운 뒤 2번과 동일하게 진행!

 

소스코드

#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 8
using namespace std;

int n,m;
int arr[MAX];
int ind[MAX];

void dfs(int index, int cnt){
    if(cnt == m){
        for(int i=0; i<m; i++){
            printf("%d ",arr[ind[i]]);
        }
        printf("\n");
        return;
    }
    
    // DFS
    for(int i=index; i<n; i++){
        ind[cnt] = i;
        dfs(i,cnt+1);
    }
}

int main(int argc, const char * argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    scanf("%d %d",&n,&m);
    for(int i=0; i<n; i++){
        arr[i] = i+1;
    }
    
    dfs(0,0);
}

 




 

15654번 N과 M(5)

 

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


 

문제

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

  • N개의 자연수 중에서 M개를 고른 수열

 

입력

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

둘째 줄에 N개의 수가 주어진다. 입력으로 주어지는 수는 10,000보다 작거나 같은 자연수이다.

 

출력

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

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

 

예제 입력

4 2
9 8 7 1

 

예제 출력

1 7
1 8
1 9
7 1
7 8
7 9
8 1
8 7
8 9
9 1
9 7
9 8

 

해결방법

수열의 값을 직접 입력받아야함!

결과 전부 맞는데 틀렸습니다…. ㅠㅠ

 

소스코드

#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 8
using namespace std;

int n,m;
int arr[MAX];
int ind[MAX];
bool check[MAX];

void dfs(int cnt){
    if(cnt == m){
        for(int i=0; i<m; i++){
            printf("%d ",arr[ind[i]]);
        }
        printf("\n");
        return;
    }
    
    // DFS
    for(int i=0; i<n; i++){
        if(!check[i]){
            check[i] = true;
            ind[cnt] = i;
            dfs(cnt+1);
            check[i] = false;
        }
    }
}

int main(int argc, const char * argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    scanf("%d %d",&n,&m);
    for(int i=0; i<n; i++){
        cin >> arr[i];
    }
    
    sort(arr, arr+n);
    dfs(0);
}

 




 

15655번 N과 M(6)

 

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


 

문제

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

  • N개의 자연수 중에서 M개를 고른 수열
  • 고른 수열은 오름차순이어야 한다.

 

입력

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

둘째 줄에 N개의 수가 주어진다. 입력으로 주어지는 수는 10,000보다 작거나 같은 자연수이다.

 

출력

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

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

 

예제 입력

4 2
9 8 7 1

 

예제 출력

1 7
1 8
1 9
7 8
7 9
8 9

 

해결방법

수열의 값을 직접 입력받아야함!

결과 전부 맞는데 틀렸습니다…. ㅠㅠ

 

소스코드

#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 8
using namespace std;

int n,m;
int arr[MAX];
int ind[MAX];
bool check[MAX];

void dfs(int index, int cnt){
    if(cnt == m){
        for(int i=0; i<m; i++){
            printf("%d ",arr[ind[i]]);
        }
        printf("\n");
        return;
    }
    
    // DFS
    for(int i=index; i<n; i++){
        if(!check[i]){
            check[i] = true;
            ind[cnt] = i;
            dfs(i,cnt+1);
            check[i] = false;
        }
    }
}

int main(int argc, const char * argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    scanf("%d %d",&n,&m);
    for(int i=0; i<n; i++){
        cin >> arr[i];
    }
    
    sort(arr, arr+n);
    dfs(0,0);
}

 




 

15656번 N과 M(7)

 

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


 

문제

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

  • N개의 자연수 중에서 M개를 고른 수열
  • 같은 수를 여러 번 골라도 된다.

 

입력

첫째 줄에 N과 M이 주어진다. (1 ≤ M ≤ N ≤ 7)

둘째 줄에 N개의 수가 주어진다. 입력으로 주어지는 수는 10,000보다 작거나 같은 자연수이다.

 

출력

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

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

 

예제 입력

4 2
9 8 7 1

 

예제 출력

1 1
1 7
1 8
1 9
7 1
7 7
7 8
7 9
8 1
8 7
8 8
8 9
9 1
9 7
9 8
9 9

 

해결방법

수열의 값을 직접 입력받아야함!

결과 전부 맞는데 틀렸습니다…. ㅠㅠ

 

소스코드

#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 8
using namespace std;

int n,m;
int arr[MAX];
int ind[MAX];
bool check[MAX];

void dfs(int cnt){
    if(cnt == m){
        for(int i=0; i<m; i++){
            printf("%d ",arr[ind[i]]);
        }
        printf("\n");
        return;
    }
    
    // DFS
    for(int i=0; i<n; i++){
        //check[i] = true;
        ind[cnt] = i;
        dfs(cnt+1);
        //check[i] = false;
    }
}

int main(int argc, const char * argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    scanf("%d %d",&n,&m);
    for(int i=0; i<n; i++){
        cin >> arr[i];
    }
    
    sort(arr, arr+n);
    dfs(0);
}

 




'Algorithm > BOJ 문제풀이' 카테고리의 다른 글

[DFS] 6603번 로또  (0) 2018.11.18
[DFS] 2309번 일곱 난쟁이  (0) 2018.11.18
[BFS] 4963번 섬의 개수  (0) 2018.11.13
[DP] 1912번 연속합  (0) 2018.11.09
[DP] 11722번 가장 긴 감소하는 부분 수열  (0) 2018.11.09