Moovie Mooving (状态压缩+二分)

题目戳这里

题意:奶牛要在电影院里呆L分钟,这段时间他要看电影度过。电影一共N部,每部都播放于若干段可能重叠的区间,奶牛决不会看同一部电影两次。现在问他要看最少几部电影才能度过这段时间? 注:必须看电影才能在电影院里呆着,同时一场电影可以在其播放区间内任意时间入场出场。

题解:设dp[s]代表已看的电影集合为s所能待到的最长时间,转移的时候枚举一个没有看过的电影,二分找到最近的开始时间,直接转移即可,详情见代码。

//n<=20 枚举其状态 dp[s] s状态下最大的滞留时间 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e3+5;
void io() { ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); }
int a[25][maxn],dp[(1<<21)+5];
int L,n,t[25],cnt[25];
//二分查找 
int find(int x,int i) {
	int l=0,r=cnt[i],res=0;
	while(l<=r) {
		int mid=(l+r)/2;
		if(x<a[i][mid]) r=mid-1;
		else l=mid+1,res=mid;
	}
	return res;
}
int main() {
	int ans=25;
	scanf("%d%d",&n,&L);
	for(int i=1;i<=n;i++) {
		scanf("%d%d",t+i,cnt+i);
		for(int j=1;j<=cnt[i];j++) scanf("%d",&a[i][j]);
	}
	memset(dp,-1,sizeof(dp));
	dp[0]=0;	//初始化 
	for(int s=0;s<1<<n;s++) {
		if(dp[s]==-1) continue;
		if(dp[s]>=L){
			ans=min(ans,__builtin_popcount(s)); //__builtin_popcount(s)统计s二进制中1的个数 
		}
		//枚举一个未观看的电影 
		for(int i=1;i<=n;i++) {
			if(!(s&(1<<(i-1)))) {
				int pos=find(dp[s],i);
				if(pos==0) continue;
				dp[s|(1<<(i-1))]=max(dp[s|(1<<(i-1))],a[i][pos]+t[i]);
			}
		}
	}
	if(ans==25) cout<<-1<<endl;
	else cout<<ans<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值