蓝桥杯——外卖店优先级

外卖店优先级

题目分析

这一题一看N,M,T的范围就知道不能暴力,要讨巧,怎么讨巧是重点。正常的思路是第一层for循环遍历订单(或者外卖店),第二层for循环遍历外卖店(或者订单),这样可以求出每个外卖店是不是在缓存里面,但是时间复杂度是 O ( N ∗ M ) = 1 e 10 > 1 e 8 O(N*M)=1e10>1e8 O(N∗M)=1e10>1e8,明显是不行的。

说一下讨巧的思路,订单我是必然要遍历的不然你不知道哪个外卖店有单子,那么可以不遍历外卖店吗?这就看我们如何处理订单了。订单应该是一个类,包含时间ts和外卖店id,我们优先对订单按照外卖店id排序,id相同时再按照ts排序,排序规则如下,

java 复制代码
static class message implements Comparable<message>{//存储订单信息
		int id,t;//订单的id和时间
		public message(int t, int id) {
			this.id = id;
			this.t = t;
		}
		@Override
		public int compareTo(message o) {
			if(this.id != o.id) {
				return this.id-o.id;
			}else {
				return this.t-o.t;
			}			
		}		
	}

现在可以开始遍历订单了,在遍历的时候我要记录两个值,一个是cnt用来表示当前外卖店的优先级大小,一个是flag用来表示当前外卖店是否被放在缓存里面。一个是ans表示我知道的在缓存里面的外卖店的数量。

java 复制代码
int flag = 0;//表示是否在优先级缓存中,在的flag=1,
int ans = 0;//记录答案
int cnt = 2;//表示外卖店的优先级大小

对于当前订单me[i],我要知道前一个订单me[i-1]是否和他是同一个外卖店,如果是,那么说明我此时把me[i-1].id的外卖店的单子都遍历完了,此时我要确定他是不是在缓存里面。两步确定法,一是确定flag是否等于1,二十确定从最后一个单子的时间到时间t内,是否会使他的优先级减少到小于等于3的情况。

java 复制代码
if(me[i].id!=me[i-1].id) {//如果变成下一个外卖店了,就要检查刚刚那个外卖店是不是在缓存中的
	//falg=1并且到达t时,没有小于等于3
	if(flag == 1 && (cnt - (t - me[i-1].t) > 3 )) {
		ans++;
	}
	cnt = 2;//此时是me[i].id有单子,那么cnt初始值应该是2
	flag = 0;//重置flag
}

否则的话,先求从上一个订单到当前这个订单,外卖店的优先级降低了多少,也就是经历的时间。那么这里为什么是int diff = me[i].t - me[i-1].t - 1;呢?举个例子,假设当前的时间是4,前一个的时间是2,那么中间没有订单的时间就是ts=3时,因此优先级应该降低1,那么也就是4-2-1。但是注意,如果出现了当前的时间是4,前一个的时间也是4,会出现4-4-1=-1的情况,但是实际此时应该优先级降低0,所以会有if(diff == -1) diff = 0;。那么这个if(cnt <= 3)一定要在cnt += 2;之前判断,举个例子,假设外卖店的当前优先级是4,那么diff=2,4减2等于2,此时应该被移出优先级缓存的,但是如果在判断之前我先给他加了2,那么此时2+2=4>3,他就不会移出优先级缓存,造成结果错误。

java 复制代码
else {
	int diff = me[i].t - me[i-1].t - 1;//优先级降低了多少 me[i].t=1  me[i-1].t=1
	if(diff == -1) diff =  0;
	cnt = Math.max(0, cnt - diff);//如果优先级降低到了负数,那么他就是0
	if(cnt <= 3) flag = 0;//如果小于等于3会被移出缓存
	cnt += 2;//出现了订单,优先级加2.
	if(cnt > 5) flag = 1;//如果大于5会被加入缓存
}

注意,最后一个外卖店,我没有判断它是否在缓存里面,所以for循环结束后要判断

java 复制代码
//对最后一个订单/最后一个外卖店进行判断
if(flag == 1 && (cnt - (t - me[m-1].t) > 3 )) {
	ans++;
}
System.out.println(ans);

题目代码

java 复制代码
import java.util.Arrays;
import java.util.Scanner;
public class Main{
	static class message implements Comparable<message>{//存储订单信息
		int id,t;//订单的id和时间
		public message(int t, int id) {
			this.id = id;
			this.t = t;
		}
		@Override
		public int compareTo(message o) {
			if(this.id != o.id) {
				return this.id-o.id;
			}else {
				return this.t-o.t;
			}			
		}		
	}
public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	int n = scanner.nextInt();
	int m = scanner.nextInt();
	int t = scanner.nextInt();
	message[] me = new message[m];
	for (int i = 0; i < me.length; i++) {
		me[i] =new message(scanner.nextInt(), scanner.nextInt());
	}
	Arrays.sort(me);
	int flag = 0;//表示是否在优先级缓存中,在的flag=1,
	int ans = 0;//记录答案
	int cnt = 2;//表示外卖店的优先级大小
	for (int i = 1; i < m; i++) {
		if(me[i].id!=me[i-1].id) {//如果变成下一个外卖店了,就要检查刚刚那个外卖店是不是在缓存中的
			//falg=1并且到达t时,没有小于等于3
			if(flag == 1 && (cnt - (t - me[i-1].t) > 3 )) {
				ans++;
			}
			cnt = 2;//此时是me[i].id有单子,那么cnt初始值应该是2
			flag = 0;//重置flag
		}else {
			int diff = me[i].t - me[i-1].t - 1;//优先级降低了多少 me[i].t=1  me[i-1].t=1
			if(diff == -1) diff =  0;
			cnt = Math.max(0, cnt - diff);
			if(cnt <= 3) flag = 0;
			cnt += 2;
			if(cnt > 5) flag = 1;
		}
	}
	//对最后一个订单/最后一个外卖店进行判断
	//讲日期模拟器的时候,whie循环结束后,也得有一个if语句,对最后一个日期进行检查
	if(flag == 1 && (cnt - (t - me[m-1].t) > 3 )) {
		ans++;
	}
	System.out.println(ans);
}
}
相关推荐
wuqingshun31415913 小时前
蓝桥杯 16. 外卖店优先级
c++·算法·职场和发展·蓝桥杯·深度优先
咚咚轩13 小时前
蓝桥杯11届国B 答疑
蓝桥杯·贪心
callJJ1 天前
Bellman - Ford 算法与 SPFA 算法求解最短路径问题 ——从零开始的图论讲解(4)
数据结构·算法·蓝桥杯·图论·单源最短路径·bellman- ford算法
a东方青1 天前
蓝桥杯 2024 C++国 B最小字符串
c++·职场和发展·蓝桥杯
咚咚轩3 天前
蓝桥杯12届国B 纯质数
蓝桥杯
qystca3 天前
P8803 [蓝桥杯 2022 国 B] 费用报销
蓝桥杯
wuqingshun3141593 天前
蓝桥杯 10. 全球变暖
c++·算法·职场和发展·蓝桥杯
咚咚轩4 天前
蓝桥杯13届国B 完全日期
蓝桥杯·枚举·日期问题
逐光沧海5 天前
数据结构基础--蓝桥杯备考
数据结构·c++·算法·蓝桥杯
吃个早饭5 天前
2025年第十六届蓝桥杯大赛软件赛C/C++大学B组题解
c语言·c++·蓝桥杯