题目链接

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

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).

输入描述:

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.

示例1
输入

4 100
50 3 15 30 55
40 2 0 65
30 2 20 90
20 1 0

输出

3

备注:
Bessie should attend the first showing of the fourth movie from time 0
to time 20. Then she watches the first showing of the first movie
from time 20 to time 65. Finally she watches the last showing of the
second movie from time 65 to time 100.

题意:

有n部电影,第i个电影时长为ai,有b个播放电影的时间,
每个电影只能看一次,且在看一部电影的过程中,不能换到另一个正在播放相同电影的放映厅。
问能不能在0~L的过程中连续不断的观看电影?如果能,最少看几部

题解:

dp问题
但是看看L的范围1≤L≤100,000,000,是个状态压缩dp
dp[a]表示在a的状态下最多可以在影院里看多长时间电影。
a是一个01串,0表示当前电影没看,1表示当前电影看过
a初始全为0,在状态转移过程中,我们要在a中找一个没看过的(值为0)且放映时间尽可能往后(但要在上一个点的电影结束之前放映或者正好衔接)
因为我们要求所看电影尽可能少,其实就是尽可能少出反应厅,或者刚从一个电影厅出来,进一个刚刚开始放映的电影,这样待的时间最长,不用频繁出来看其他电影,所以就要选所看电影的放映时间尽可能往后

因为a是一个二分串,当时间超过l时,我们可以直接查询当前状态二进制有多少1,也就是多少电影
起始时间的查找需要用二分

本人理解,不知道对不对
查询二进制多少个1可以自定义函数,也可以用__builtin_popcount(i), 这个函数是返回二级制i中1的个数
我看好多人都在用这个

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 30;
int a[maxn];
vector<int> G[maxn];
int ans=30; 
int dp[1 << maxn];
int n,l;
int sum(int x)
{
    int ans=0;
    while(x)
    {
        if(x)
        {
            ans++;
        }
        x>>=1;
    }
    return ans;
}
int main()
{

    cin>>n>>l;

    for(int i=0;i<n;++i)
    {
        cin>>a[i];
        cin>>m;
        for(int j=0;j<m;j++)
        {
            int x;
            cin>>x;
            G[i].push_back(x);
        }
    }
    for(int i=1;i<(1<<n);++i)
    {
        for(int j=0;j<n;++j) 
        {
            if(i&(1<<j)) 
            {
                int w=i^(1<<j);
                int pos=upper_bound(G[j].begin(),G[j].end(),dp[w])-G[j].begin()-1;
                if (pos)
                {
                         dp[i]=max(dp[i],G[j][it]+a[j]);
                }

            }
        }
     //   if(dp[i]>=l) ans=min(ans,__builtin_popcount(i)); 
         if(dp[i]>=l) 
         {
             ans=min(ans,sum(i)); 
         }
    if(ans==30)ans=-1; 
    cout<<ans;
    return 0;