案例:外卖店优先级

分析:

这是一道模拟题,朴素的求解思路是:将M条订单信息先按时间从小到大排序、时间相同再按外卖店序号从小到大排序,时间复杂度为O(MlogM);然后依次处理每条订单信息,对每条订单信息,可能要更新N家外卖店的优先级,所以时间复杂度为O(MN)。注意,所有订单都是T时刻以内的

上述算法的时间复杂度是O(MN),当1≤N,M,T≤10000时,是可以在1秒之内运算完毕的。但如果N,M,T取到100000,上述算法就不能在1秒之内运算完毕了

在处理每条订单信息时,为什么可能要更新N家外卖店的优先级呢?因为:假设每条订单的时间不同,则该订单的外卖店优先级要增加,其他外卖店的优先级要降低。但如果前后几条订单的时间相同呢?哪些外卖店优先级要调整,很复杂! 

定义两个数组:
1)p:长度为N,保存N家外卖店的优先级,每个元素初值为0
2)last:长度为N,保存N家外卖店上一个订单的时刻,每个元素初值为0

更好的求解思路是:1)合并订单——时间相同、外卖店相同的订单统一处理;2)对每条订单,只调整对应外卖店优先级,其他外卖店不用处理,因为st数组保存了每家外卖店上一个订单的时刻,所以这样处理完全是可行的
该算法的时间复杂度为:max(O(MlogM), O(M), O(N) )

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int maxn = 100010;
const int maxm = 100010;
int N, M, T;
int p[maxn];  //记录每家外卖店的优先级(初值为0) 
int last[maxn];  //记录每家外卖店上一个订单时刻(初值为0)
bool st[maxn];  //每家外卖店是否在优先缓存中的标志
PII order[maxm];  //存M条订单 
int main(){
	cin >> N >> M >> T;
	for(int i=0;i<M;i++)
		cin >> order[i].first >> order[i].second;
	//二级排序:先按时刻,再按外卖店序号 
	sort(order, order+M);
	for(int i=0;i<M; ){
		int j = i;
		while(j<M and order[j]==order[i]) j++;  //时间和外卖点编号都相同的订单
		int t = order[i].first, id = order[i].second, cnt = j-i;  //cnt:订单数
		i = j;
		p[id] -= t - last[id] - 1;  //先减去没有订单的时刻(t时刻是有订单)
		if(p[id]<0) p[id] = 0;
		if(p[id]<=3) st[id] = false;  //退出优先缓存
		p[id] += cnt*2;
		if(p[id>5])  st[id] = true;
		last[id] = t;  //维护外卖店的last 
	} 
	for(int i=1;i<=N;i++){
		if(last[i]<T){
			p[i] -= T - last[i];
			if(p[i]<=3)  st[i] = false;
		}
	} 
	int ans = 0;
	for(int i=1;i<=N;i++)
		ans += st[i];	
	cout << ans << endl;
	return 0;
} 

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值