写在前面小声bb,这是第二次写,第一次写的时候写到一半点到了b站,没有保存。。。。还有英语题对英语渣渣太不友好了。。。

题意

母牛去看电影,要在电影院待满L时间,给出n个电影,以及每部电影的持续时间,每部电影播放m次,给出每次开始播放的时间,现在给出一个方案要求母牛全程都在看电影最少的看的部数,允许母牛电影看到一半跑出来,但是不允许出来之后又去看同一部电影。

输入描述

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.
1 <= N <= 20 ; 1 <= L <= 100,000,000 (我就不把题目也复制过来凑字数了)

输出描述

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.

思路

首先看到这个题目就想到应该是用贪心或者用dp来做。
然后因为N<20,并且观看电影的顺序会有影响,所以要记录状态,所以我们考虑状压dp。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

inline int read() {
    int s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}

const int N = 20;
vector<int> v[N];
int dp[1 << N];
int a[N];

int main(){
    int n=read(),l=read();
    int ans=30;
    for(int i=0;i<n;++i){
        a[i]=read();
        int m=read();
        while(m--)v[i].push_back(read());
    }
    for(int i=1;i<1<<n;++i){
        for(int j=0;j<n;++j) {
            if(i&(1<<j)) {
                int tmp=i^(1<<j);
                int it=upper_bound(v[j].begin(),v[j].end(),dp[tmp])-v[j].begin()-1;
                if (it>=0)
                    dp[i]=max(dp[i],v[j][it]+a[j]);
            }
        }
        if(dp[i]>=l) ans=min(ans,__builtin_popcount(i));   //这个函数是返回二级制i中1的个数
    }
    if(ans!=30) printf("%d\n",ans);
    else  puts("-1");
    return 0;
}