版权声明:本文为博主原创,未经博主允许不得转载 https://blog.csdn.net/Sherry_Yue/article/details/88539942
华华听月月唱歌
题目描述
月月唱歌超级好听的说!华华听说月月在某个网站发布了自己唱的歌曲,于是把完整的歌曲下载到了U盘里。然而华华不小心把U盘摔了一下,里面的文件摔碎了。月月的歌曲可以看成由1到N的正整数依次排列构成的序列,它现在变成了若干个区间,这些区间可能互相重叠。华华想把它修复为完整的歌曲,也就是找到若干个片段,使他们的并集包含1到N(注意,本题中我们只关注整数,见样例1)。但是华华很懒,所以他想选择最少的区间。请你算出华华最少选择多少个区间。因为华华的U盘受损严重,所以有可能做不到,如果做不到请输出-1。
输入描述:
第一行两个正整数N、M,表示歌曲的原长和片段的个数。
接下来M行,每行两个正整数L、R表示第i的片段对应的区间是[L,R]。
输出描述:
如果可以做到,输出最少需要的片段的数量,否则输出-1。
示例1
输入
4 2
1 2
3 4
输出
2
示例2
输入
4 2
1 1
3 4
输出
-1
示例3
输入
10 5
1 1
2 5
3 6
4 9
8 10
输出
4
备注:
解题思路:
考虑贪心,将所有区间按照左端点排序,从左往右遍历。用一个变量维护我们当前最远可以够到的右端点,然后枚举左端点不超过右端点+1的所有区间,选择右端点最靠右的一个即可。时间复杂度O(NlogN)。
解题代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 1e5+5;
struct node
{
int l, r;
}a[MAX];//存储M个片段区间
bool cmp(node a, node b){return a.l<b.l;}
int main()
{
int N, M;//歌曲的原长和片段的个数
int ans = 0;//计数最少区间
int MaxDis = 0;//标记最远可以够到的右端点
int i = 1;//遍历1到M个片段
while( cin >> N >> M )
{
for(int i=1;i<=M;++i)
cin >> a[i].l >> a[i].r;
sort(a+1,a+M+1,cmp);//第一个元素存储在a[1]
while( MaxDis<N )//当最远可以够到的右端点小于歌曲的原长时
{
//遍历区间左端点不超过之前区间最远右端点+1的所有区间,
//选择右端点最靠右的一个,并用temp记录其值
int temp = 0;
while( a[i].l<=MaxDis+1 && i<=M )
{
temp = max(a[i].r,temp);
++i;
}
if( temp>=MaxDis )//当temp>=之前标记的最远可以够到的右端点时
{
MaxDis = temp;//更新最远可以够到的右端点的值
++ans;//计数+1
}
else//否则代表区间中间断开了,即区间的并集不全部包含1到N
{
ans = -1;
break;
}
}
}
cout << ans << endl;
}