N과 M
백트래킹(Backtracking)
- 한정 조건을 가진 문제를 풀려는 전략
- 어떤 노드의 유망성 점검 후, 유망하지 않으면 그 노드의 부모노드로 되돌아가서 다른 자손 노드를 검색함
15649번 N과 M(1)
문제
자연수 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)
문제
자연수 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)
문제
자연수 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)
문제
자연수 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)
문제
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)
문제
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)
문제
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 |