题意:让你安排课程,保证每学期的课不能冲突,问最少需要几个学期。
solution:
因为 n 只有15,可以考虑状压dp。用二进制每位的1/0表示当前是否学习该课程,可以得到 n 个二进制位,那么所有的可能性有 1<<n 种,预处理 g[s] 表示 s 所代表课程的是否可以在一个学期内学完(对于当前要学的所有课程的学时进行标记,若有重复标记则不可能在一学期学完),f[s] 维护学完当前课程所花费的最少学期,枚举子集进行转移。 答案的状态应该是所有课全部修完,即 $f[(1<<n)-1]$。时间复杂度 $O(2^n m n)$。
Code 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 #include <bits/stdc++.h> using namespace std ;const int N = 1 << 15 ;int n, m, sum, f[N], g[N], b[20 ], a[20 ][105 ], vis[105 ];bool check (int x) { memset (vis, 0 , sizeof (vis)); for (int i = 0 ; i < n; i++) { if (x >> i & 1 ) { for (int j = 1 ; j <= b[i]; j++) { if (vis[a[i][j]]) return false ; vis[a[i][j]] = 1 ; } } } return true ; } int main () { cin >> n >> m; for (int i = 0 ; i < n; i++) { cin >> b[i]; for (int j = 1 ; j <= b[i]; j++) cin >> a[i][j]; } memset (f, 0x3f , sizeof (f)); f[0 ] = 0 ; sum = (1 << n) - 1 ; for (int s = 0 ; s <= sum; ++s) { g[s] = check(s); for (int t = s; t; t = (t - 1 ) & s) if (g[t]) f[s] = min (f[s], f[s ^ t] + 1 ); } cout << f[sum] << '\n' ; return 0 ; }