POJ - 3190区间贪心+优先队列

本文探讨了使用贪心策略解决区间分组问题,旨在将无交集的区间进行分组,以达到最少组数的目标。文章分享了两种贪心策略的思考过程及其实现难点,最终介绍了一种利用优先队列实现O(nlogn)复杂度的高效解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

十分迷的一个贪心题。

题意,给你若干区间,让你分成若干组,要求每组中的区间都不能有交集,并要求组数最少。

很容易想到区间调度问题:给你若干区间,选取若干,要求其中的区间不能有交集,最多能取多少区间.

区间调度问题的贪心策略是,每一次都选取最早结束的区级,也就是右端点最小的区间,那么最后选取的区间数一定最多.

 

于是我基于区间调度问题,想到两种贪心策略:

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;	
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值