순열은 무엇일까요? 재귀를 이용하여 순열을 뽑기 전에 순열은 어떤 모양을 가지고 있는지
알아야 함으로 어떻게 생겼는지 먼저 알아봅시다.
순열은 Permutation 으로 nPr n개의 나열된 숫자에서 r개를 뽑는 것을 말합니다.
예를 들어 1, 2, 3, 4 의 숫자에서 2개의 숫자를 뽑는다면 경우는
위와 같이 같은 숫자를 가진 집합이 존재하면서 뽑히게 됩니다. 1 2와 2 1이 같은 경우로 치지 않고 뽑히는 경우
달라진다면 순열로 뽑는것이 옳고 1 2와 2 1이 같은 것이라면 조합으로 뽑아야 시간을 줄일 수 있겠죠?
조합은 위에 말한것처럼 순열의 반의 가짓수를 뽑는다고 생각하시면 좀 더 이해하기 쉬울 것 같습니다.
ㅇ 조합에 대한 이야기는 다음 블로그 글을 참조하시면 됩니다.
https://www.acmicpc.net/problem/15649
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<stdio.h>
#include<vector>
using namespace std;
int N, M;
const int DSIZE = 9;
const int chkSIZE = 9;
int D[DSIZE];
int chk[chkSIZE];
void dfs(int idx) {
if (idx == M) {
for (int i = 0; i < M; i++) printf("%d ", D[i]);
printf("\n");
return;
}
for (int i = 1; i <= N; i++) {
if (chk[i] == 0) {
chk[i] = 1;
D[idx] = i;
dfs(idx + 1);
D[idx] = 0;
chk[i] = 0;
}
}
}
void init() {
scanf("%d %d", &N, &M);
}
int main(void) {
init();
dfs(0);
return 0;
}
|
https://www.acmicpc.net/problem/15654
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
|
#include<stdio.h>
#include<algorithm>
using namespace std;
int N, M;
const int inputSIZE = 8;
const int chkSIZE = 8;
const int DSIZE = 8;
int input[inputSIZE];
int D[DSIZE];
int chk[chkSIZE];
void init() {
scanf("%d %d", &N, &M);
for (int i = 0; i < N; i++) {
scanf("%d", &input[i]);
}
sort(input, input + N);
}
void dfs(int idx) {
if (idx == M) {
for (int i = 0; i < M; i++)printf("%d ", D[i]);
printf("\n");
}
for (int i = 0; i < N; i++) {
if (chk[i] == 0) {
chk[i] = 1;
D[idx] = input[i];
dfs(idx + 1);
D[idx] = 0;
chk[i] = 0;
}
}
}
int main(void) {
init();
dfs(0);
return 0;
}
|
위에 처음 문제와 다른점은 내가 입력한 숫자에 대해서 오름차순으로 뽑는 것입니다.
기본 틀에서 입력으로 받은 배열을 정렬을 해주고
i의 값을 D의 배열에 넣어서 한경우는 1-N N이 8이 최대인 경우에서 는 i값을 넣어도 되지만
입력받은 숫자를 넣어야 하므로 input [i]를 넣어주어야 정확한 결과를 얻을 수 있습니다.
https://www.acmicpc.net/problem/15663
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
46
47
48
49
50
51
52
53
54
55
56
|
#include<stdio.h>
#include<vector>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
map <vector<int>, int> m;
int N, M, ret;
const int doubleChkSIZE = 10001;
const int DSIZE = 8;
const int chkSIZE = 8;
int doubleChk[doubleChkSIZE];
vector<int>D;
int chk[chkSIZE];
vector<int>input;
void init() {
scanf("%d %d", &N, &M);
for (int i = 0; i < N; i++) {
int data = 0;
scanf("%d", &data);
input.push_back(data);
}
sort(input.begin(), input.end());
}
void dfs(int idx) {
if (idx == M) {
for (int i = 0; i < M; i++) {
printf("%d ", D[i]);
}
printf("\n");
return;
}
int before = 0;
for (int i = 0; i < input.size(); i++) {
if (chk[i] == 0&&before!=input[i]){
before = input[i];
chk[i] = 1;
D.push_back(input[i]);
dfs(idx + 1);
D.pop_back();
chk[i] = 0;
}
}
}
int main(void) {
int T;
//scanf("%d", &T);
for (int tc = 1; tc <= 1; tc++) {
init();
dfs(0);
//printf("#%d %d\n", tc, ret);
}
return 0;
}
|
cs |
앞서 봤던 문제에 비해서 좀 더 생각을 해야 하는 문제입니다.
입력을 받은 수에 예를 들어 9 7 9 1 이면 정렬 시 1 7 9 9 가 되는데
이때 그냥 뽑게 되면 1 7 / 1 9 / 1 9 / 이렇게 정말 완전 같은 수를 가지게 뽑게 됩니다.
이수를 뽑지 않게 하기 위해서는 D 공간에 넣기전에 우선 중복이 되면 안되니까 중복 체크하는
chk 배열을 체크하고 before라는 변수를 두어 현재 정렬되어있으므로 이전의 값과 현재 지금
들어가서 D공간에 입력되는 값이 다른 경우만 넣어주게 되면 위의 문제는 해결될 수 있습니다.
이해가 안 되면 우선 코드를 입력해보시고 어떻게 결과가 나오게 되는지 확인해보시면 이해하기
수월할 것입니다.
중복순열
중복 순열은 이전에 봤던 순열과 비슷합니다. 아래의 문제를 보면서 이해해 봅시다.
https://www.acmicpc.net/problem/15651
1.
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
|
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
const int DSIZE = 8;
const int chkSIZE = 9;
int D[DSIZE];
int chk[chkSIZE];
int N, M;
void init() {
scanf("%d %d", &N, &M);
}
void dfs(int idx) {
if (idx == M) {
for (int i = 0; i < M; i++)printf("%d ", D[i]);
printf("\n");
}
for (int i=1; i <= N; i++) {
if (idx < M) {
D[idx] = i;
dfs(idx + 1);
D[idx] = 0;
}
}
}
int main(void) {
init();
dfs(0);
return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
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
|
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
const int DSIZE = 8;
const int chkSIZE = 9;
char D[16];
int chk[chkSIZE];
int N, M;
void init() {
scanf("%d %d", &N, &M);
}
void dfs(int idx) {
if (idx >= (M-1)*2) {
printf("%s\n", D);
return;
}
D[idx++] = ' ';
for (int i=1; i <= N; i++) {
D[idx] = '0' + i;
dfs(idx + 1);
}
}
int main(void) {
init();
for (int i = 1; i <= N; i++) {
D[0] = '0' + i;
dfs(1);
}
return 0;
}
|
cs |
위의 소스는 좀 더 빠른 방식으로 할 수 있는 방법으로 배열에 저장을 할 때 띄움도
같이 넣어야 하므로 M*2인데 dfs에서 (M-1)* 2 인 이유는 dfs를 들어오기 전에
제일 처음 값은 넣고 시작하기 때문에 M-1입니다.
그렇게 해서 이해하시면 빠르시고 그냥 나는 저런 방법 너무 복잡해서 어렵다 하면 1번 방식을 외우시면 됩니다.
https://www.acmicpc.net/problem/15656
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
|
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
int N, M;
const int DSIZE = 8;
const int inputSIZE = 8;
int D[DSIZE];
int input[inputSIZE];
void init() {
scanf("%d %d", &N, &M);
for (int i = 0; i < N; i++) {
scanf("%d", &input[i]);
}
sort(input, input + N);
}
void dfs(int idx) {
if (idx == M) {
for (int i = 0; i < M; i++) printf("%d ", D[i]);
printf("\n");
return;
}
for (int i = 0; i < N; i++) {
if (idx < M) {
D[idx] = input[i];
dfs(idx + 1);
D[idx] = 0;
}
}
}
int main(void)
{
init();
dfs(0);
return 0;
}
|
위의 문제와 별 다를 바 없습니다 i를 D에 넣어줬던 것을 input [i]로만 넣어주면 되는 것입니다.
정말 문제들이 비슷비슷해서 쉽지 않나요?
처음이라 어렵다고 생각이 들어도 여러 번 반복하면서 익히다 보면 언젠가는
나 자신의 것이 될 것입니다. 포기하지 마세요.
여기까지 오시느라 수고 많으셨고 정말 알고 보면 쉽지 않습니까? 당연한 소리 같지만
반복을 통해 익숙해서 나만의 것으로 만들어보면 비슷한 유형의 문제를 풀어도
겁이 안 날것입니다.
위에 소스가 완벽한 소스가 아니고 제가 의식의 흐름에 따라 작성한 소스라 빼도 되는
부분이 있을 것이고 할 것인데 참고 정도로만 생각해주시고 위의 소스를 기반으로 더 완벽한
소스를 만들어보시면 좋을 것 같습니다.
대게 소스를 배열 기반으로 했지만 백터 기반으로도 가능하니 백터를 이용한 방식으로도 해보셔도
좋다고 생각합니다.
오늘은 여기까지이고 감사합니다.
'알고리즘 모음집 > 알고리즘 (Algorithm)' 카테고리의 다른 글
백준 16197 두 동전 (0) | 2019.09.08 |
---|---|
조합의 모든것 풀어봅시다 (0) | 2019.08.20 |
백준 1244 스위치 켜고 끄기 (0) | 2019.07.28 |
백준 1941 소문난 칠공주 (0) | 2019.07.28 |
백준 1182 부분수열의 합 (0) | 2019.07.24 |
댓글