NOIP模拟---movie

题头

【描述】
小石头喜欢看电影,选择有 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;
}
原文地址:https://www.cnblogs.com/forever-/p/9736084.html