알고스팟 소풍
https://algospot.com/judge/problem/read/PICNIC
algospot.com :: PICNIC
소풍 문제 정보 문제 안드로메다 유치원 익스프레스반에서는 다음 주에 율동공원으로 소풍을 갑니다. 원석 선생님은 소풍 때 학생들을 두 명씩 짝을 지어 행동하게 하려고 합니다. 그런데 서로 친구가 아닌 학생들끼리 짝을 지어 주면 서로 싸우거나 같이 돌아다니지 않기 때문에, 항상 서로 친구인 학생들끼리만 짝을 지어 줘야 합니다. 각 학생들의 쌍에 대해 이들이 서로 친구인지 여부가 주어질 때, 학생들을 짝지어줄 수 있는 방법의 수를 계산하는 프로그램을 작성하세요
algospot.com
<접근방법>
n이 매우 작기 때문에 완전탐색으로 풀 수 있겠다고 생각했다.
단, 중복을 없애고 고르는 것이 관건이라고 생각했다. 그래서 처음에는 nC2를 n/2번 하면 되겠다고 생각했다. 그런데 구현도 못하겠고 답이 이상하다.
책에 나온 방법을 예시로 설명하면
n = 6이 일때,
(0, 1)(?, ?)(?, ?)/................../(1, 0)(?, ?)(?, ?)
(1, 0)이 나오기 전까지만 갯수를 세었다.
구현방법은 무조건 (순번이 빠른 사람, 순번이 느린 사람) 이렇게 고르게 만드는 것이다.
그러면 중복이 없이 카운팅을 할 수 있다.
<시간복잡도>
완전탐색이므로 최대 갯수를 세어보자.
열 명의 학생이 모두 친구인 경우가 그렇다.
9 * 7 * 5 * 3 * 1 = 945이다.
<코드>
#include <iostream>
#include <algorithm>
#include <memory.h>
using namespace std;
int tc, n, m;
int areFriend[10][10], visit[10];
int make() {
int low = -1;
for (int i = 0; i < n; i++) {
if (visit[i] == 0) {
low = i;
break;
}
}
if (low == -1) return 1;
int res = 0;
for(int i = low+1; i < n; i++){
if (visit[i] == 1 || areFriend[low][i] == 0) continue;
visit[low] = visit[i] = 1;
//printf("c : %d %d\n", low, i);
res += make();
visit[low] = visit[i] = 0;
}
return res;
}
int main() {
scanf("%d", &tc);
while (tc--) {
//초기화
memset(visit, 0, sizeof(visit));
memset(areFriend, 0, sizeof(areFriend));
scanf("%d %d", &n, &m);
for (int i = 0; i < m; i++) {
int a, b;
scanf("%d %d", &a, &b);
areFriend[a][b] = 1;
areFriend[b][a] = 1;
}
printf("%d\n", make());
}
return 0;
}
<느낀 점>
생각못한 접근방법이다. 외워둬야겠다.