取包裹(对线段贪心 set+lower_bound)

4 篇文章 0 订阅
该博客介绍了一种贪心策略来解决有n件包裹,每次可以取k件的问题。每个包裹有入库时间和最晚取走时间,目标是最少次数取出所有包裹。通过将包裹按最晚取走时间排序,然后从小到大遍历,决定是否能与之前包裹一起取走,从而优化取件次数。代码中使用了C++实现,包括map和set的数据结构。
摘要由CSDN通过智能技术生成

LINK

题目

在这里插入图片描述

大致题意

有n件包裹,每次可以取k件。给出每件包裹入库时间和最晚取走时间。(入库当天和最晚取走当天都可以取快递)问:最少几次可以将所有包裹取出。

思路

贪心。最小的 r r r一定要有一次把它取出来,所以每次在最小 r r r当天取出包裹即最优。
r r r从小到大排序,遍历,每次都对最小的 r r r进行处理。
如果当前 l l l小于等于确定去快递点的时间 r r r时,就和离 l l l最进时间点 r r r一起取走,此时确定去快递点的时间 r r r拿包裹的件数加一,若此时那确定去快递点的时间 r r r拿满了,说明不能之后的包裹无法在此时刻 r r r拿,即删除此 r r r
如果当前 l l l大于所有已存的确定去快递点的时间 r r r就当前 r r r时间时拿一次( a n s + + ans++ ans++),并且记录此时刻取包裹件数为1。
(大牛思路)

代码

#include<bits/stdc++.h>
using namespace std;
//#define ll long long
#define int long long
const int N = 1e5+10;
const double eps=1e-8;
struct node{//记录r最小 
	int l;int r;
	bool operator <(const node &a)const{
		if(r!=a.r) return r<a.r; 
		return l<a.l ;
	}
}ar[N];
map<int,int>mp;
set<int>se;
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int t,ans,n,k;cin>>t;
	while(t--){
		cin>>n>>k;
		ans=0;mp.clear();se.clear();
		for(int i=0,l,r;i<n;i++){
			cin>>ar[i].l>>ar[i].r;
		}
		if(k==1){
			cout<<n<<endl;continue;
		}
		sort(ar,ar+n);//r从小到大 
		for(int i=0;i<n;i++){//r从小到大 遍历 
			auto pos=se.lower_bound(ar[i].l );
			//判断此包裹是否可以和前面某次一起取走 
			if(pos==se.end()){//无法一起取走
				mp[ar[i].r ]=1;//此时刻拿一次包裹,包裹容量为1 
				se.insert(ar[i].r );  
				ans++;//取快递点次数加一
			}else{//可以一起取走 
				int x=*pos; 
				if(++mp[x]==k)se.erase(x);//增加一件,若包裹容量满了则删除 
			}
		} 
		cout<<ans<<endl;
	} 
	return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值