Moovie Mooving(状压DP)
Moovie Mooving
https://ac.nowcoder.com/acm/problem/24158
题目:
n部电影,有时长和若干放映起始时间。Bessie可以在某部电影的放映阶段去看这部电影或中途离开。他不会看同一部电影2次。问Bessie最少需要看几部电影使得他在0~L时间段内一直看电影。(n最大20)
做法:
状压DP。 表示在
状态下Bessie能连续看电影到的最远时间。
是二进制状态。第i位为1表示第i部电影已经看过,0表示没看过。转移的时候就找一个
中的一个0将它置1。表示下一部要看的电影就是它。然后在这部电影的放映时间vector中二分第一个比当前时间小的放映时间
。用
+电影时长更新就好了。
转移:
统计最少的电影数量:
代码:
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
typedef long long ll;
const int N = 21;
const int inf = 0x3f3f3f3f;
int movie_time[N], dp[1<<N];
vector<int> movie_begin[N];
int get(int id, int x){
int p = upper_bound(movie_begin[id].begin(), movie_begin[id].end(), x) - movie_begin[id].begin();
if (p == 0) return 0;
return movie_begin[id][p-1]+movie_time[id];
}
int cntbit(int sta){
int cnt = 0;
for (int i = sta; i >= 1; i -= i&(-i)) cnt++;
return cnt;
}
int main(void){
IOS;
int n, L; cin >> n >> L;
for (int i = 1; i <= n; ++i){
cin >> movie_time[i];
int m; cin >> m;
for (int j = 1; j <= m; ++j){
int x; cin >> x;
movie_begin[i].push_back(x);
}
}
for (int i = 1; i <= n; ++i){
if (movie_begin[i][0] == 0) dp[1<<(i-1)] = movie_time[i];
}
int ans = inf;
for (int i = 1; i < (1<<n); ++i){
if (dp[i] >= L) ans = min(ans, cntbit(i));
for (int j = 0; j < n; ++j){
if (((i>>j)&1) == 0){
dp[i|(1<<j)] = max(dp[i|(1<<j)], get(j+1, dp[i]));
}
}
}
if (ans == inf) ans = -1;
cout << ans << endl;
return 0;
}
查看22道真题和解析