P3118 [USACO15JAN]Moovie Mooving G
题目描述
Bessie is out at the movies. Being mischievous as always, she has decided to hide from Farmer John for L (1 <= L <= 100,000,000) minutes, during which time she wants to watch movies continuously. She has N (1 <= N <= 20) movies to choose from, each of which has a certain duration and a set of showtimes during the day. Bessie may enter and exit a movie at any time during one if its showtimes, but she does not want to ever visit the same movie twice, and she cannot switch to another showtime of the same movie that overlaps the current showtime. Help Bessie by determining if it is possible for her to achieve her goal of watching movies continuously from time 0 through time L. If it is, determine the minimum number of movies she needs to see to achieve this goal (Bessie gets confused with plot lines if she watches too many movies).
'
奶牛贝西想连续看L (1 <= L <= 100,000,000)分钟的电影,有 N (1 <= N <= 20) 部电影可供选择,每部电影会在一天的不同
时段放映。
贝西可以在一部电影播放过程中的任何时间进入或退出放映厅。但她不愿意重复看到一部电影,所以每部电影她最多看到
一次。她也不能在看一部电影的过程中,换到另一个正在播放相同电影的放映厅。
请帮贝西计算她能够做到从 0 到 L 分钟连续不断地观看电影,如果能,请计算她最少看几部电影就行了。'
输入
The first line of input contains N and L. The next N lines each describe a movie. They begin with its integer duration, D (1 <= D <= L) and the number of showtimes, C (1 <= C <= 1000). The remaining C integers on the same line are each in the range 0..L, and give the starting time of one of the showings of the movie. Showtimes are distinct, in the range 0..L, and given in increasing order.
输出
A single integer indicating the minimum number of movies that Bessie
needs to see to achieve her goal. If this is impossible output -1
instead.
样例输入
4 100
50 3 15 30 55
40 2 0 65
0 2 20 90
20 1 0
样例输出
3
状态压缩 dp + 二分。
一开始看错题了,以为要看够 (L) 分钟,结果写了半天才发现是要从 (0) 一直看到 (L)
看到 (n) 的范围那么小 , (L) 的范围那么大,我们可以考虑把 (L) 的值压入数组中。
设 $f[s] $ 表示看电影集合为 (s) 的时候,看电影能持续到多长时间。
转移时我们可以枚举这个状态所有能看的电影,就会有转移。
f[i] = max(f[i], a[j][t] + t[i]) (i&(1<<j-1) == 1)
(t) 是使 (a[j][t]) >= f [i ^ (1<<(j-1))] 的数,即播放时间大于不看这部电影的延续的最长时间。
因为下一个电影的合法开始时间越晚,答案肯定更优。
最后收集答案就枚举每个状态,看这个状态的延续时间是否大于 (L), 如果大于就把这个状态看电影的个数和答案取个 (min)
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,k,ans = 2147483647;
int t[55],num[55],movie[55][1010],f[2097152];
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s =s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
int lower__bound(int now,int k)
{
int L = 1, R = num[now], res = -1;
while(L <= R)
{
int mid = (L + R)>>1;
if(movie[now][mid] <= k)
{
res = mid;
L = mid + 1;
}
else R = mid - 1;
}
return res;
}
int main()
{
n = read(); k = read();
for(int i = 1; i <= n; i++)
{
t[i] = read(); num[i] = read();
for(int j = 1; j <= num[i]; j++)
{
movie[i][j] = read();
}
}
for(int i = 1; i < (1<<n); i++)
{
for(int j = 1; j <= n; j++)
{
if(i & (1<<(j-1)))
{
int id = lower__bound(j,f[i ^ (1<<(j-1))]);//找第一个大于 k 的数
if(id != -1)
{
f[i] = max(f[i], movie[j][id] + t[j]);
}
}
}
}
for(int i = 1; i < (1<<n); i++)
{
if(f[i] >= k)
{
int cnt = 0, x = i;
while(x)
{
cnt += x&1;
x >>= 1;
}
ans = min(ans,cnt);
}
}
if(ans == 2147483647) printf("%d
",-1);
else printf("%d
",ans);
return 0;
}