题头
【描述】
小石头喜欢看电影,选择有 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
还算简单吧,但好像暴力很不好写;
一看N的范围就是个状压dp了,而且是贪心,让当前电影最晚结束,然后乱搞一通差不多就出来了
我旁边的大佬%%%%%用随机化贪心过了90分%%%%%
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
inline int read(){
char ch;
while((ch=getchar())<'0'||ch>'9'){; }
int res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return res;
}
int n,m,tim[25],num[25],c[22][1005],s,ans,f[1<<21];
inline int find(int x,int id)
{
int l=-1,r=num[id]-1,mid,ans;
while(l<r) {
int mid=l+r+1>>1;
if(c[id][mid]<=x)l=mid;
else r=mid-1;
}
return l;
}
int main(){
n=read(),m=read();
for(int i=0;i<n;i++)
{
tim[i]=read();
num[i]=read();
for(int j=0;j<num[i];j++)
{
c[i][j]=read();
}
}
ans=inf;
s=1<<n;
memset(f,-1,sizeof(f)); f[0]=0;
for(int i=0;i<s;i++)
{
if(f[i]==-1) continue;
if(f[i]>=m)
{
int j=0;
for(int k=i;k;k-=(k&-k))j++;
ans=min(ans,j);
continue;
}
for(int j=0;j<n;j++)
{
if(i&(1<<j)) continue;
int k=find(f[i],j);
if(k==-1) continue;
f[i|(1<<j)]=max(f[i|(1<<j)],c[j][k]+tim[j]);
}
}
if(ans==inf) cout<<-1<<endl;
else cout<<ans<<endl;
}