版权声明:虽然我只是个小蒟蒻但转载也请注明出处哦 https://blog.csdn.net/weixin_42557561/article/details/82183828
电影
描述
小石头喜欢看电影,选择有N部电影可供选择,每一部电影会在一天的不同时段播放。他希望连续看L分钟的电影。因为电影院是他家开的,所以他可以在一部电影播放过程中任何时间进入或退出,当然他不希望重复看一部电影,所以每部电影他最多看一次,也不能在看一部电影的时候,换到另一个正在播放一样电影的放映厅。
请你帮助小石头让他重0到L连续不断的看电影,如果可以的话,计算出最少看几部电影。
输入
第一行是2个整数N,L,表示电影的数量,和小石头希望看的连续时间 接下来是N行,每行第一个整数D(1<=D<=L)表示电影播放一次的播放时间,第二个整数是C表示这部电影有C次播放,接下来是C个整数表示C次播放的开始时间Ti(0<=Ti<=L),Ti是按升序给出
输出
一个整数,表示小石头最少看的电影数量,如果不能完成输出-1
样例输入
4 100
50 3 15 30 55
40 2 0 65
30 2 20 90
20 1 0
样例输出
3
【样例说明】
开始他选择最后一步电影从0时间开始。
到了20分钟,他选择第一部电影的第一次播放,看到65分钟
最后他选择第二部电影的第二次播放,从65分钟到100分钟
【数据规模】
30%数据N<=10
100%数据N<=20, 1 <= L <= 100,000,000 ,C<=1000
分析
首先观察数据范围,很小,自然想到了状压dp(因为每个电影都对下一次的选择有影响)
然后定义 f [ i ] 表示 i 这个状态下,最多能看多长的时间。每次转移的时候用贪心的思想,枚举每一部电影,然后二分查找开片时间小于等于当前 f [ i ] 的那一场,这样看的时间才会最长
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#define in read()
#define ll long long
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+ch-48;ch=getchar();}
return f==1?res:-res;
}
int n,ti,f[1100000];
struct node{int len,c.t[1005];}a[25];
inline int find(int x,int id){//二分查找,贪心插入
int l=1,r=a[id].c,ans=-1;
while(l<=r){
int mid=l+r>>1;
if(a[id].t[mid]<=x) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
int main(){
n=in;ti=in;
int i,j,k,status=(1<<n),ans=25;
ll sum=0;
for(i=1;i<=n;++i){
a[i].len=in;a[i].c=in;
for(j=1;j<=a[i].c;++j) a[i].t[j]=in;
}
memset(f,-1,sizeof(f));
f[0]=0;
for(i=0;i<status;++i){
if(f[i]==-1) continue;
if(f[i]>ti){
int tot=0;
for(j=0;j<n;++j)
if((1<<j)&i) tot++;
ans=min(ans,tot);
}
for(j=1;j<=n;++j){
if(i&(1<<j-1)) continue;
k=find(f[i],j);
if(k==-1) continue;//第j部电影没办法插入
f[i|(1<<j-1)]=max(f[i|(1<<j-1)],a[j].t[k]+a[j].len);
}
}
if(ans==25) printf("-1");
else printf("%d",ans);
return 0;
}