1. 程式人生 > 實用技巧 >P3118 [USACO15JAN]Moovie Mooving G

P3118 [USACO15JAN]Moovie Mooving G

P3118 [USACO15JAN]Moovie Mooving G

題目描述

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

奶牛貝西想連續看L (1 <= L <= 100,000,000)分鐘的電影,有 N (1 <= N <= 20) 部電影可供選擇,每部電影會在一天的不同

時段放映。

貝西可以在一部電影播放過程中的任何時間進入或退出放映廳。但她不願意重複看到一部電影,所以每部電影她最多看到

一次。她也不能在看一部電影的過程中,換到另一個正在播放相同電影的放映廳。

請幫貝西計算她能夠做到從 0 到 L 分鐘連續不斷地觀看電影,如果能,請計算她最少看幾部電影就行了。'

輸入

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.

樣例輸入

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

樣例輸出

3


狀態壓縮 dp + 二分。

一開始看錯題了,以為要看夠 \(L\) 分鐘,結果寫了半天才發現是要從 \(0\) 一直看到 \(L\)

看到 \(n\) 的範圍那麼小 , \(L\) 的範圍那麼大,我們可以考慮把 \(L\)

的值壓入陣列中。

設 $f[s] $ 表示看電影集合為 \(s\) 的時候,看電影能持續到多長時間。

轉移時我們可以列舉這個狀態所有能看的電影,就會有轉移。

f[i] = max(f[i], a[j][t] + t[i]) (i&(1<<j-1) == 1) 

\(t\) 是使 \(a[j][t]\) >= f [i ^ (1<<(j-1))] 的數,即播放時間大於不看這部電影的延續的最長時間。

因為下一個電影的合法開始時間越晚,答案肯定更優。

最後收集答案就列舉每個狀態,看這個狀態的延續時間是否大於 \(L\), 如果大於就把這個狀態看電影的個數和答案取個 \(min\)

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,k,ans = 2147483647;
int t[55],num[55],movie[55][1010],f[2097152];
inline int read()
{
	int s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s =s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
int lower__bound(int now,int k)
{
	int L = 1, R = num[now], res = -1;
	while(L <= R)
	{
		int mid = (L + R)>>1;
		if(movie[now][mid] <= k)
		{
			res = mid;
			L = mid + 1;
		}
		else R = mid - 1;
	}
	return res;
}
int main()
{
	n = read(); k = read();
	for(int i = 1; i <= n; i++)
	{
		t[i] = read(); num[i] = read();
		for(int j = 1; j <= num[i]; j++)
		{
			movie[i][j] = read();
		}
	}
	for(int i = 1; i < (1<<n); i++)
	{
		for(int j = 1; j <= n; j++)
		{
			if(i & (1<<(j-1)))
			{
				int id = lower__bound(j,f[i ^ (1<<(j-1))]);//找第一個大於 k 的數
				if(id != -1)
				{
					f[i] = max(f[i], movie[j][id] + t[j]);
				}
			}
		}
	}
	for(int i = 1; i < (1<<n); i++)
	{		
		if(f[i] >= k)
		{
	
			int cnt = 0, x = i;
			while(x)
			{
				cnt += x&1;
				x >>= 1;
			}
			ans = min(ans,cnt);
		}
	}
	if(ans == 2147483647) printf("%d\n",-1);
	else printf("%d\n",ans);
	return 0;
}