【2018/08/29测试T3】【SDOJ 3729】电影

【题目】

题目描述:

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

【分析】

状压DP,用 f[ i ] 表示从 0 开始最远能连续看到哪

转移的时候,枚举没有看过的电影,贪心选取能看的片场中最靠后的那一个

我们可以用二分来找要选的那一部电影

时间复杂度O(2^{N}\cdot N\cdot log \, C

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 25
#define C 1005
#define inf 1ll<<31ll-1
#define lowbit(x) x&(-x)
using namespace std;
int d[N],c[N],t[N][C],f[1<<N];
int find(int x,int id)
{
	int l,r,mid;
	l=-1,r=c[id];
	while(l<r)
	{
		mid=(l+r+1)>>1;
		if(t[id][mid]<=x)  l=mid;
		else  r=mid-1;
	}
	return l;
}
int main()
{
//	freopen("movie.in","r",stdin);
//	freopen("movie.out","w",stdout);
	int n,l,i,j;
	scanf("%d%d",&n,&l);
	int status=1<<n;
	for(i=1;i<=n;++i)
	{
		scanf("%d%d",&d[i],&c[i]);
		for(j=1;j<=c[i];++j)
		  scanf("%d",&t[i][j]);
	}
	memset(f,-1,sizeof(f));
	f[0]=0;
	int ans=inf;
	for(i=0;i<status;++i)
	{
		if(f[i]==-1)
		  continue;
		if(f[i]>=l)
		{
			int num=0;
			for(j=i;j;j-=lowbit(j))
			  num++;
			ans=min(ans,num);
			continue;
		}
		for(j=1;j<=n;++j)
		{
			if(i&(1<<j-1))
			  continue;
			int pos=find(f[i],j);
			if(pos==-1)  continue;
			f[i|(1<<j-1)]=max(f[i|(1<<j-1)],t[j][pos]+d[j]);
		}
	}
	if(ans==inf)  printf("-1");
	else  printf("%d",ans);
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/82184019