十分迷的一个贪心题。
题意,给你若干区间,让你分成若干组,要求每组中的区间都不能有交集,并要求组数最少。
很容易想到区间调度问题:给你若干区间,选取若干,要求其中的区间不能有交集,最多能取多少区间.
区间调度问题的贪心策略是,每一次都选取最早结束的区级,也就是右端点最小的区间,那么最后选取的区间数一定最多.
于是我基于区间调度问题,想到两种贪心策略:
1.枚举所有区间,每次以一个区间为起点,每一步选取后面的最早结束的区间,然后标记;再以下一个没标记的区间为起点开始选取.
用这种方法交了一发,tle,我估计策略是正确的,但在全(1,10)这种情况下o(n*n)的复杂度会爆
2.每次在剩下的区间里面选择合法的最早结束的区间(相当于不断重复区间调度)
一是不好写,二是估计也和方法1一样会tle
然后看了下题解,发现是用优先队列....(开始也想到,但用的方法显然不一样)
首先我说下一开始想到一种与正确思路类似的想法:
依旧是按照结束时间自早到晚,每次对于某个区间,如果在之前的区间组合里面,有能够安放的位置
就放过去,不然就新开一个组合,我是想着用vector,但觉得这样还是会超时(没想到用优先队列以及相应的贪心策略)
正确思路:
正确的贪心策略很无语,就是自左向右,对于一个区间,如果之前有和它没有交集的区间,就用这个区间更新那个区间
否则就新建立一个区间,而如果有若干没有交集的区间,就任意放一个(应该是这样,也不确定),然后用优先队列
可以o(nlog n)实现,不然暴力n方会爆.
只能说想不到可以任意放,而且优先队列竟然可以这样用.
附一个优先队列的博客:http://blog.sina.com.cn/s/blog_4e5157120100vn7b.html
写得不太好的ac代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn=100010;
const int inf=0x3f3f3f3f;
int n,ans,cnt;
int vis[maxn];
vector<int> vec[maxn];
struct node
{
int x,y,z;
friend bool operator <(const node &a,const node &b)
{
return a.y>b.y||(a.y==b.y&&a.x>b.x);
}
}a[maxn];
bool cmp(const node &a,const node &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int main()
{
while(~scanf("%d",&n)){
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
a[i].z=i;
}
sort(a,a+n,cmp);
priority_queue <node> que;
que.push(a[0]);
vis[a[0].z]=++cnt;
ans++;
for(int i=1;i<n;i++){
node temp=que.top();
if(a[i].x>temp.y){
vis[a[i].z]=vis[temp.z];
que.pop();
que.push(a[i]);
}else {
ans++;
cnt++;
vis[a[i].z]=cnt;
que.push(a[i]);
}
}
printf("%d\n",ans);
for(int i=0;i<n;i++){
printf("%d\n",vis[i]);
}
}
return 0;
}