728x90

부분수열의 합

문제

N개의 정수로 이루어진 수열이 있을 때, 크기가 양수인 부분수열 중에서 그 수열의 원소를 다 더한 값이 S가 되는 경우의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 20, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.

출력

첫째 줄에 합이 S가 되는 부분수열의 개수를 출력한다.


이번문제는 백트레킹! 부분수열의 합 입니다.

n개의 원소중에서 m개를 뽑았을때 합이 S 이면 결과값을 늘려나가는 방법을 이용했습니다.

여기서 m개의 범위는 1 <= m <=n 으로 하였습니다.

기본적으로 nCm (1<=m<=n) 일때 결과값이 S인 것을 찾는다고 생각하면 좋을것 같습니다.

 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n, m;
int a[20];
vector<int> v;
int check[20];
int ans;
void dfs(int depth, int next, int k)
{
    if (depth == k)
    {
        int sum = 0;
        for (int i = 0; i < n; i++)
            sum += a[i];
        if (sum == m) ans++;
 
        return;
    }
    for (int i = next; i < n; i++)
    {
        if (!check[i])
        {
            check[i] = true;
            a[depth] = v[i];
            dfs(depth + 1, i + 1, k);
            check[i] = false;
        }
    }
}
int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        int k;
        cin >> k;
        v.push_back(k);
    }
    for(int i=1;i<=n;i++)
        dfs(00, i);
    cout << ans;
    return 0;
}
cs
LIST
728x90

N과 M (4)

문제

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

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

입력

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

출력

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

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


지금까지 순열, 조합, 중복 순열을 알아봤습니다.

마지막으로 중복 조합에 대해서 공부해 보겠습니다.

중복 조합에서는 next 인자의 값을 증가시키지 않고 전달하여 for문에서 다시 i=next 부터 찾도록? 구현해보았습니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;
 
int n, m, a[8], c[8];
void dfs(int depth, int next)
{
    if (depth == m)
    {
        for (int i = 0; i < m; i++)
            cout << a[i] + 1 << ' ';
        cout << '\n';
        return;
    }
    for (int i = next; i < n; i++)
    {
        a[depth] = i;
        dfs(depth + 1, i);
    }
}
int main()
{
    cin >> n >> m;
    dfs(00);
    return 0;
}
cs
LIST
728x90

문제

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

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

입력

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

출력

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

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

예제 입력 1

3 1

예제 출력 1

1
2
3

예제 입력 2

4 2

예제 출력 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

 이번 문제는 backtracking 에서 순열 입니다
 
해결 방법으로는 여러가지가 있는데, 저는 방문체크 배열을 이용하여 문제를 해결해 보겠습니다.
 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;
//방문했는지 체크하는 배열
bool check[100];
//방문하지 않았으면 숫자가 들어가는 배열
int arr[10];
//nPm
int n, m;
void permutation(int depth)
{
//m개 를 선택했을 경우
    if (depth == m)
    {
        for (int i = 0; i < m; i++)
            cout <<arr[i]+1 << ' ';
        cout << '\n';
        return;
    }
    for (int i = 0; i < n; i++)
    {
        if (!check[i])
        {
            check[i] = true;
            arr[depth] = i;
            permutation(depth + 1);
            check[i] = false;
        }
    }
}
int main()
{
    cin >> n >> m;
    permutation(0);
    return 0;
}
cs

 

LIST
728x90

문제

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다.

N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (1 ≤ N < 15)

출력

첫째 줄에 퀸 N개를 서로 공격할 수 없게 놓는 경우의 수를 출력한다.

 

예제 입력 1

8

예제 출력 1

92

 


 

backtracking의 첫 문제는 n-queen 문제로 정했습니다.

n x n 의 행렬에 대각선, 가로, 세로가 겹치지 않도록 모든 행에 말을 두어 그 경우의수를 출력하는 문제입니다.

 

풀이 순서는 다음과 같습니다.

 

1. 모든 행에 말 배치하기

 

2. 가로 세로 대각선이 겹치지 않는다면 말을 두기

 

3. 모든행의 말을 두었다면 결과값 업데이트

 


코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <stdlib.h>
#define MAX 15
using namespace std;
//n * n행
int n;
//arr[k] -> 세로 위치(y값), k -> 가로위치(x값)
int arr[MAX];
int ans;
bool isPossiable(int depth)
{
    for(int i=1;i<depth;i++)
    {
        // y값이 일치하는지 확인     //대각선에 위치하는지 확인
        if(arr[depth] == arr[i] || depth-== abs(arr[depth] - arr[i]))
            return false;
    }
    return true;
}
void dfs(int depth)
{
    //depth가 1부터 시작으로 했을때 이므로 n+1로 설정한다.
    if(depth == n+1)
    {
        ans++;
        return;
    }
    for(int i=1;i<=n;i++)
    {
        arr[depth] = i;
        if(isPossiable(depth))
            dfs(depth+1);
    }
}
int main()
{
    cin >> n;
    dfs(1);
    cout << ans;
    return 0;
}
cs
LIST

+ Recent posts