반응형
출처: https://algospot.com/judge/problem/read/GRADUATION
Approach
비트마스크 (Bitmask)
비트마스크 정수의 이진수 표현(Bit)을 자료 구조로 쓰는 기법 현대의 모든 CPU는 이진수를 이용해도 모든 자fy 표현 내부적으로 이진수를 사용하는 컴퓨터들은 이진법 관련 연산들을 아주 빨리
zoosso.tistory.com
과목의 수 = 4
들어야 할 과목의 수 = 4
학기 수 = 4
한 학기에 최대 들을 수 있는 과목의 수 = 4
- 첫번째 학기) 0, 3 과목 이수
- 두번째 학기) 1 과목 이수
- 세번째 학기) 2 과목 이수
graduate(int semester, int taken)
= 현재 학기가 semeter 이고, 지금까지 들은 과목의 집합이 taken일 때,
앞으로 다녀야 하는 최소 학기의 수는?
- 어떤 과목의 선수 과목을 이미 전부 들었는지 확인 → taken과 prerequisite[i] 교집합
- canTake 변수로 아직 선수 과목을 다 듣지 않아 들을 수 없는 과목을 필터
결과적으로 이번 학기에 들을 수 있는 과목만이 caTake 변수에 저장됨
- bitCount() 함수로 이미 들은 과목의 수나 이번 학기에 들을 과목의 수를 셉니다.
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define INF 987654321
#define MAX 12
// n: 전공과목 수 k: 들어야할 과목의 수
// m: 학기 수 l: 한 학기에 최대로 들을 수 있는 과목의수
int n, k, m, l;
// prerequiiste[i] = i번째 과목의 선수과목의 집합
int prerequisite[MAX];
// classes[i] = i번째 학기에 개설되는 과목의 집합
int classes[10];
int cache[10][1 << MAX];
// N의 이진수 표현에서 켜진 비트의 수 반환
int bitcount(int n){
if (n == 0)return 0;
return n % 2 + bitcount(n / 2);
}
// 현재 학기 semester, 들은 과목의 수 taken
int graduate(int semester, int taken){
// k개 이상의 과목을 이미 들은 경우
if (bitcount(taken) >= k) return 0;
// 주어진 학기내에서 모든 과목을 이수하지 못한 경우
if (semester == m) return INF;
int &ret = cache[semester][taken];
if (ret != -1) return ret;
ret = INF;
// 이번 학기에 들을 수 있는 과목 중 아직 듣지 않은 과목들을 찾는다
int canTake = (classes[semester] & ~taken);
// 선수 과목을 다 듣지 않은 과목들을 걸러낸다
for (int i = 0; i < n; i++){
if ((canTake&(1 << i)) && (taken&prerequisite[i]) != prerequisite[i])
canTake &= ~(1 << i);
}
//최소 학기 수 비교
for (int take = canTake; take>0; take = ((take - 1)&canTake)){
// 한 학기에 최대 l개 까지만 들을 수 있다
if (bitcount(take) > l) continue;
ret = min(ret, graduate(semester + 1, taken | take) + 1);
}
// 이번 학기에 아무 것도 듣지 않을 경우
ret = min(ret, graduate(semester + 1, taken));
return ret;
}
int main(){
int c; cin >> c;
while (c--){
memset(prerequisite, 0, sizeof(prerequisite));
memset(classes, 0, sizeof(classes));
memset(cache, -1, sizeof(cache));
cin >> n >> k >> m >> l;
// 과목별 선행 과목 정보
for (int i = 0; i < n; i++){
int preNum; cin >> preNum;
for (int j = 0; j < preNum; j++){
int subject; cin >> subject;
prerequisite[i] |= (1 << subject);
}
}
// 한 학기에 열리는 과목 개수
for (int i = 0; i < m; i++){
int classNum; cin >> classNum;
for (int j = 0; j < classNum; j++){
int subject; cin >> subject;
classes[i] |= (1 << subject);
}
}
int res = graduate(0, 0);
if (res == INF) cout << "IMPOSSIBLE\n";
else cout << res << '\n';
}
}
반응형
'PS 문제 풀이 > Algospot' 카테고리의 다른 글
[Algospot] 알고스팟 INSERTION 삽입 정렬 뒤집기 (0) | 2021.03.01 |
---|---|
[Algospot] 알고스팟 NERD2 너드인가, 너드가 아닌가? 2 (0) | 2021.03.01 |
[Algospot] 알고스팟 FORTRESS 요새 (0) | 2021.03.01 |
[Algospot] 알고스팟 TRAVERSAL 트리 순회 순서 변경 (0) | 2021.03.01 |
[Algospot] 알고스팟 ITES 외계 신호 분석 (0) | 2021.03.01 |
댓글