P4151 电影节
题目链接:4151:电影节.
题目描述
总时间限制: 1000ms 内存限制: 65536kB
描述
大学生电影节在北大举办! 这天,在北大各地放了多部电影,给定每部电影的放映时间区间,区间重叠的电影不可能同时看(端点可以重合),问李雷最多可以看多少部电影。
输入
多组数据。每组数据开头是n(n<=100),表示共n场电影。
接下来n行,每行两个整数(0到1000之间),表示一场电影的放映区间
n=0则数据结束
输出
对每组数据输出最多能看几部电影
样例输入
8
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
0
样例输出
3
题解
方法一:贪心算法
思路
将所有电影按照结束时间从小到大进行排序,看的第一部电影选择结束时间最早的那部,然后接下来每次选择电影都应该满足:开始时间晚于上一部电影的结束时间且结束时间最早。
证明该贪心算法的有效性。
证明:(替换法)
假设使用贪心算法(也就是上述算法)得到的电影序列为: a 1 、 a 2 、 a 3 . . . a_1、a_2、a_3... a1、a2、a3...
不用该算法所挑选出来的最长电影序列为: b 1 、 b 2 、 b 3 . . . b_1、b_2、b_3... b1、b2、b3...
现证明:对于 ∀ i , b i {\forall}\ i,b_i ∀ i,bi 可以被替换为 a i a_i ai
对于电影 x x x, x x x 的开始时间是 S ( x ) S(x) S(x),结束时间是 E ( x ) E(x) E(x)
使用数学归纳法:
- 当 i = 1 i=1 i=1 时
因为 E ( a 1 ) ⩽ E ( b 1 ) E(a_1)\leqslant E(b_1) E(a1)⩽E(b1),所以 b 1 b_1 b1 可以被替换为 a 1 a_1 a1- 当 i > 1 i>1 i>1 时,假设 b i − 1 b_{i-1} bi−1 可以被替换为 a i − 1 a_{i-1} ai−1
因为 E ( a i − 1 ) ⩽ E ( b i − 1 ) E(a_{i-1})\leqslant E(b_{i-1}) E(ai−1)⩽E(bi−1)、 E ( b i − 1 ) ⩽ S ( b i ) E(b_{i-1})\leqslant S(b_i) E(bi−1)⩽S(bi),所以 E ( a i − 1 ) ⩽ S ( b i ) E(a_{i-1})\leqslant S(b_i) E(ai−1)⩽S(bi)
由上述的贪心算法,可以知道: E ( a i ) = min ( E ( x ) , x ∈ s e t ) , s e t = { x ∣ E ( a i − 1 ) ⩽ S ( x ) } E(a_i)=\min(E(x),x\in set),set=\{x|E(a_{i-1})\leqslant S(x)\} E(ai)=min(E(x),x∈set),set={x∣E(ai−1)⩽S(x)} 所以 E ( a i ) ⩽ E ( b i ) E(a_i)\leqslant E(b_i) E(ai)⩽E(bi)
又因为 b i − 1 b_{i-1} bi−1 可以被替换为 a i − 1 a_{i-1} ai−1
所以 b i b_i bi 可以被替换为 a i a_i ai综上,由数学归纳法,对于 ∀ i , b i {\forall}\ i,b_i ∀ i,bi 可以被替换为 a i a_i ai 得证。
所以该贪心算法有效。
对于上面的证明,你可能还有一个疑问,假如序列 b 1 、 b 2 、 b 3 . . . b_1、b_2、b_3... b1、b2、b3... 比序列 a 1 、 a 2 、 a 3 . . . a_1、a_2、a_3... a1、a2、a3... 要长,那么序列 b 1 、 b 2 、 b 3 . . . b_1、b_2、b_3... b1、b2、b3... 多出来的一部分无法被替换。
假设序列 a 1 、 a 2 、 a 3 . . . a_1、a_2、a_3... a1、a2、a3... 的最后一个元素为 a k a_k ak,序列 b 1 、 b 2 、 b 3 . . . b_1、b_2、b_3... b1、b2、b3... 存在 b k + 1 b_{k+1} bk+1,因为 b 1 、 b 2 、 b 3 . . . b k b_1、b_2、b_3\ ...\ b_k b1、b2、b3 ... bk 已经被替换为了 a 1 、 a 2 、 a 3 . . . a k a_1、a_2、a_3\ ...\ a_k a1、a2、a3 ... ak,所以 E ( a k ) ⩽ S ( b k + 1 ) E(a_k)\leqslant S(b_{k+1}) E(ak)⩽S(bk+1),由上述贪心算法,序列 a 1 、 a 2 、 a 3 . . . a_1、a_2、a_3... a1、a2、a3... 的最后一个元素必定不是 a k a_k ak,因为 ∃ b k + 1 {\exists}\ b_{k+1} ∃ bk+1,满足 E ( a k ) ⩽ S ( b k + 1 ) E(a_k)\leqslant S(b_{k+1}) E(ak)⩽S(bk+1),那么 a k a_k ak 之后还会加入电影 a k + 1 a_{k+1} ak+1 到序列 a 1 、 a 2 、 a 3 . . . a_1、a_2、a_3... a1、a2、a3... 中,假设不成立。
算法
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct Film{
int begin;
int end;
bool operator<(const Film& right)const{
return end<right.end;
}
};
int main(){
int n;
while(scanf("%d",&n),n!=0){
vector<Film> films(n);
for(int i=0;i<n;++i){
scanf("%d %d",&films[i].begin,&films[i].end);
}
sort(films.begin(),films.end());
int count=1;
int endTime=films[0].end;
for(int i=1;i<n;++i){
if(films[i].begin>=endTime){
++count;
endTime=films[i].end;
}
}
printf("%d\n",count);
}
}
复杂度分析
假设电影节所放映的全部电影的场数为 n n n
- 时间复杂度: O ( n log n ) O(n\log n) O(nlogn),进行排序的时间复杂度为 O ( n log n ) O(n\log n) O(nlogn),将所有电影遍历一遍 O ( n ) O(n) O(n),这两个程序段是并列的关系,所以总的时间复杂度为: O ( max { n log n , n } ) = O ( n log n ) O(\max\{n\log n,n\})=O(n\log n) O(max{nlogn,n})=O(nlogn)
- 空间复杂度: O ( n ) O(n) O(n)