【题解】sdoj3729电影 状压DP(2018-08-06集训T3)

25 篇文章 0 订阅
12 篇文章 0 订阅

题目链接

问题描述

小石头喜欢看电影,选择有 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


题解

状压 DP, f[i]表示状态为 i 时从 0 最远连续看到哪。
然后转移时候, 枚举还要看哪部电影,贪心取能看的片场中最靠后的一个。
然后时间复杂度 O(2^N×N×x)
其中 x 是求能看片场中最靠后一个的时间复杂度。
求法 1:
二分。 x=log2C
求法 2:
类似单调队列预处理,然后 x=1

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int N=25;
int n,l;
int S;
int len[N],movie[N][1010];
int f[1<<N];//f[i]表示状态为i时能看的最长时间 
int p[N];
int find(int x,int id)
{
    int l=-1,r=p[id]-1,mid;
    while(l<r)
    {
        mid=(l+r+1)>>1;
        if(movie[id][mid]<=x)l=mid;
        else r=mid-1;
    }
    return l;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int i,j,k,ans=INF;
    scanf("%d%d",&n,&l);
    S=1<<n;
    for(i=0;i<n;i++)
    {
        scanf("%d%d",&len[i],&p[i]);
        for(j=0;j<p[i];j++)scanf("%d",&movie[i][j]);
    }
    memset(f,-1,sizeof(f));
    f[0]=0;
    for(i=0;i<S;i++)
    {
        if(f[i]==-1)continue;
        if(f[i]>=l)
        {
            for(j=0,k=i;k;k-=k&(-k))j++;
            ans=min(ans,j);
            continue;
        }
        for(j=0;j<n;j++)
        {
            if(i&(1<<j))continue;
            k=find(f[i],j);
            if(k==-1)continue;
            f[i|(1<<j)]=max(f[i|1<<j],movie[j][k]+len[j]);
        }
    }
    if(ans==INF)puts("-1");
    else printf("%d\n",ans);
    return 0;
}

比赛时看数据规模感觉是状压DP来着……但是写不来

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值