题意
传送门 P3118 [USACO15JAN]Moovie Mooving
题解
爆搜至少
O
(
N
!
)
O(N!)
O(N!),考虑状态压缩
D
P
DP
DP。
d
p
[
i
]
dp[i]
dp[i] 代表集合
i
i
i 中电影全部的排列能达到的最大
t
t
t,使
[
0
,
t
]
[0,t]
[0,t] 都被电影覆盖。
d
p
[
i
∣
1
<
<
j
]
=
m
a
x
0
≤
j
<
N
且
i
>
>
j
&
1
=
0
{
d
p
[
i
∣
1
<
<
j
]
,
u
p
p
e
r
_
b
o
u
n
d
(
d
p
[
i
]
)
+
D
[
j
]
}
dp[i|1<<j]=max_{0\leq j<N且i>>j\&1=0}\{dp[i|1<<j],upper\_bound(dp[i])+D[j]\}
dp[i∣1<<j]=max0≤j<N且i>>j&1=0{dp[i∣1<<j],upper_bound(dp[i])+D[j]} 答案为满足
d
p
[
i
]
≥
L
dp[i]\geq L
dp[i]≥L 的电影数最小的
i
i
i,那么照拓扑
D
P
DP
DP 的做法
B
F
S
BFS
BFS 求解即可。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 20
#define maxc 1000
int N, L, D[maxn], C[maxn], B[maxn][maxc];
int cnt[1 << maxn], deg[1 << maxn], dp[1 << maxn];
int main()
{
scanf("%d%d", &N, &L);
for (int i = 0; i < N; i++)
{
scanf("%d%d", D + i, C + i);
for (int j = 0; j < C[i]; j++)
{
scanf("%d", B[i] + j);
}
}
int n = 1 << N;
for (int i = 1; i < n; i++)
{
deg[i] = cnt[i] = cnt[i >> 1] + (i & 1);
}
queue<int> q;
q.push(0);
int res = -1;
while (!q.empty())
{
int s = q.front();
q.pop();
if (dp[s] >= L)
{
res = cnt[s];
break;
}
for (int i = 0; i < N; i++)
{
if (!(s >> i & 1))
{
int nxt = s | 1 << i, j = upper_bound(B[i], B[i] + C[i], dp[s]) - B[i] - 1;
dp[nxt] = max(dp[nxt], D[i] + (j == -1 ? -inf : B[i][j]));
if (--deg[nxt] == 0)
{
q.push(nxt);
}
}
}
}
printf("%d\n", res);
return 0;
}