728x90
재귀호출을 사용한 간단한 예제문제를 풀어보겠습니다
example)
각 학생들의 쌍에 대해 서로 친구일 때만 짝을 지을 수 있는 방법의 개수를 구해보자
첫 줄에 테스트 케이스 C(C<=50)
각 테스트 케이스의 첫 줄에는 학생의 수 n(2<=n<=10), 친구 쌍의 수 m(0<=m<=n(n-1)/2)이 주어진다
그 다음줄에는 m개의 친구 쌍에 대한 정보가 주어진다
- 재귀호출 사용시 주의점
재귀호출을 사용할 경우 같은 답을 중복으로 세는 경우가 흔하게 발생하게 됩니다.
이를 해결하기 위한 가장 좋은 방법은 "사전순"으로, 즉 "가장 먼저 오는 답" 하나만을 세는 것입니다.
예를들어 (2,3) (0,1) 또는 (1,0) (2,3) 은 count 하지 않지만
(0,1) (2,3) 은 count 할 수 있는것입니다.
이 속성을 사용하기 위해서, "선택되지 않은 학생들 중에 가장 번호가 빠른 학생의 짝만 찾아주도록" 하면 됩니다.
이렇게 한다면 앞의 2가지 잘못된 경우를 해결할 수 있을지 살펴봅시다.
1. (2,3) (0,1) 의 경우 가장 빠른 학생부터 짝을 지어주기 때문에 성립할 수 없습니다.
2. (1,0) (2,3) 의 경우 가장 빠른 학생의 짝은 번호가 더 클 수 밖에 없기때문에 (1,0)은 성립할 수 없습니다.
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <vector>
using namespace std;
int friends[10][10];
int checkPair(bool isChecked[10], int N) {
// 남은 사람들 중 가장 번호가 빠른 학생을 찾는다
int firstFriend = -1;
for(int i=0; i<N; i++) {
if(!isChecked[i]) {
firstFriend = i;
break;
}
}
// 기저 사례 : 만약 짝을 지을 남은 사람이 없으면 방법을 찾은것이므로 종료한다
if(firstFriend == -1) return 1;
int ret = 0;
// 짝을 지을 사람을 결정한다
for(int next = firstFriend + 1; next < N; next++) {
if(!isChecked[next] && friends[firstFriend][next]) {
isChecked[next] = isChecked[firstFriend] = 1;
ret += checkPair(isChecked,N);
isChecked[next] = isChecked[firstFriend] = 0;
}
}
return ret;
}
int main()
{
int c,n,m;
scanf("%d",&c);
for(int j=0; j<c; j++) {
scanf("%d %d",&n,&m);
for(int i=0; i<m; i++) {
int a,b;
scanf("%d %d",&a,&b);
// 한쪽이 친구면 다른쪽도 친구다
friends[a][b] = 1;
friends[b][a] = 1;
}
bool isChecked[10];
int result = checkPair(isChecked,n);
printf("%d\n",result);
for(int l=0; l<10; l++)
for(int k=0; k<10; k++)
friends[l][k] = 0;
}
}
입력
| 3 2 1 0 1 4 6 0 1 1 2 2 3 3 0 0 2 1 3 6 10 0 1 0 2 1 2 1 3 1 4 2 3 2 4 3 4 3 5 4 5 |
출력
| 1 3 4 |
728x90
'algorithm' 카테고리의 다른 글
| c++)백준 1759 - 암호 만들기 (0) | 2021.07.01 |
|---|---|
| c++) 백준 1018 - 체스판 다시 칠하기 (0) | 2021.07.01 |
| c++)백준 1065-한수 (0) | 2021.07.01 |
| c++) 6장 - 시계 맞추기 (0) | 2021.06.29 |
| c++) 조합 구현하기 (0) | 2021.06.23 |