📙 Algorithm Solving/Java
📙[Algo] BOJ10978. 기숙사 재배정
혜덕hyeduck
2024. 10. 18. 21:01
https://www.acmicpc.net/problem/10978
문제 요약
- N명의 학생이 있고 N개의 기숙사가 있다
- 모든 학생들은 본인이 살았던 봄학기 기숙사에서 가을 학기에 다른 기숙사로 배정되면 이사를 해야하므로 기숙사 재배정을 신청하였다
- 이렇게 모든 학생들은 기숙사 재배정을 신청했지만, 학생복지팀에서는 어떤 학생에게도 기숙사 재배정을 해주지 않으려고 한다.
- 봄학기때 기숙사를 이미 배정받은 상태에서, 가을학기 기숙사에 아무도 재배정이 되지 않는 경우의 수를 구해보자
시간 제한
- 1초
입력
- 첫 번째 줄에 테스트 케이스의 수 T가 주어진다.
- 각 케이스의 첫 번째 줄에 학생 명수(기숙사의 개수) N (1 ≤ N ≤ 20) 이 주어진다.
출력
- 각 테스트 케이스 별로 아무도 재배정이 되지 않는 경우의 수를 출력한다.
접근법
- 문제를 잘 이해해보면, 학생들이 첫날 배정받은 기숙사가 아닌 다른 기숙사를 재배정 받을 경우 가능한 경우의 수를 구하는 문제이다. (문제에서 재배정을 하지 않은 모든 경우의 수를 구하라 했으므로)
- 따라서, 만약 학생들 번호가 0 ~ N-1이고, 처음 배정받은 기숙사번호도 각각 0~N-1이라 가정했을 때,
- 현재 번호랑 일치하지 않는 경우(cur != i)만 기숙사를 선택했다.
- 이때, 중복해서 기숙사를 배정하면 안되므로 방문체크를 해야하는데, 나는 비트마스킹으로 처리했다. ⇒ 나중에 DP메모이제이션 할 때, 지금까지 선택한 값도 고려하기 위해서
- N이 20이기 때문에, 학생마다 최대 19개씩 선택할 수 있으므로 시간초과가 뜬다.(19^20) ⇒ 따라서 dp메모이제이션으로 중복 계산을 없앴다.
코드
import java.io.*;
import java.util.*;
public class Main {
static int N;
static long[][] dp = new long[21][1 << 20];
static long recur(int cur, int state) {
if (cur == N) return 1;
if (dp[cur][state] != -1) return dp[cur][state];
long ret = 0;
for (int i = 0; i < N; i++) {
if (cur == i || (state & (1 << i)) > 0) continue;
ret += recur(cur + 1, state | (1 << i));
}
dp[cur][state] = ret;
return ret;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine());
long ret;
StringBuilder sb = new StringBuilder();
while (T-- > 0) {
N = Integer.parseInt(br.readLine());
for (long[] d1 : dp) {
Arrays.fill(d1, -1);
}
ret = recur(0, 0);
sb.append(ret).append("\\n");
}
System.out.println(sb);
}
}