[蓝桥杯 2019 省 A] 外卖店优先级

一.题目

题目描述

“饱了么”外卖系统中维护着 N 家外卖店,编号 1∼N
每家外卖店都有一个优先级,初始时 (0时刻) 优先级都为 0

每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减到 0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2

如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;如果优先级小于等于 3,则会被清除出优先缓存。

输入格式

第一行包含 3 个整数 N,M,T

以下 M 行每行包含两个整数 tsid,表示 ts 时刻编号 id 的外卖店收到一个订单。

输出格式

输出一个整数,代表答案。

数据范围

1 ≤ N,M,T ≤ 105 ,
1 ≤ ts ≤ T,
1 ≤ id ≤ N

输入样例

2 6 6
1 1
5 2
3 1
6 2
2 1
6 2

输出样例

1

样例解释

6 时刻时,1 号店优先级降到 3,被移除出优先缓存;2 号店优先级升到 6,加入优先缓存。

所以是有 1 家店 (2 号) 在优先缓存中。

二.解释

看到这种题目,我们直接模拟整个计算过程就好,但是模拟的角度有所不同:

1.从时间的角度:

我们可以模拟从 0 时刻到 T 时刻,每个时刻看看有哪些 id 在这一时刻有单在计算,但是这种算法复杂度有点超,不能全解;

2.从商家的角度:

我们遍历每个商家,取出所有这个商家的单,根据时间先后来排序,通过计算时间差来优化复杂度,可以AC。

三.代码

1.从时间的角度:
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <cmath>
#include <string>
#include <vector>
#include <cstring>
#include <queue>
#include <unordered_map>

using namespace std;

typedef long long int64;
typedef pair<int, int> PII;

const int MaxN = 1e5 + 10;

int InN, InM, InT, Res;			//商家数量,单数量,最大时间
vector<int> Ns[MaxN];			//Ns[1]代表id为1的商家在哪些时刻有单
int Map[MaxN];					//Map[1]代表id为的优先指数
unordered_map<int, int> PList;	//记录优先商家

int main()
{
	cin >> InN >> InM >> InT;
	int a, b;
	for (int i = 1; i <= InM; i++)
	{
		scanf("%d%d", &a, &b);
		Ns[a].push_back(b);
	}

	for (int i = 1; i <= InT; i++)	//遍历每一时刻
	{
		unordered_map<int, int> M;
		for (auto& Tmp : Ns[i])	//这一时刻有单
		{
			Map[Tmp] += 2;
			M[Tmp]++;
			if (Map[Tmp] > 5)
			{
				PList[Tmp]++;
			}
		}

		for (int j = 1; j <= InN; j++)	//这一时刻没单
		{
			if (!M.count(j))
			{
				Map[j] = max(0, Map[j] - 1);
				if (Map[j] <= 3) { PList.erase(j); }
			}
		}
	}

	cout << PList.size();

	return 0;
}
2.从商家的角度:
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <cmath>
#include <string>
#include <vector>
#include <cstring>
#include <queue>
#include <unordered_map>
#include <map>

using namespace std;

typedef long long int64;
typedef pair<int, int> PII;

const int MaxN = 2e5 + 10;

int InN, InM, InT, Res;			//商家数量,单数量,最大时间
map<int, vector<int>> Ns;		//Ns[1]代表id为1的商家在vector<int>时刻有单
int Map[MaxN];					//Map[1]代表id为的优先指数
unordered_map<int, int> PList;	//记录优先商家

int main()
{
	cin >> InN >> InM >> InT;
	int a, b;
	for (int i = 1; i <= InM; i++)
	{
		scanf("%d%d", &a, &b);
		Ns[b].push_back(a);
	}
	
	for (auto& Tmp1 : Ns)	//遍历每个商家
	{
		sort(Tmp1.second.begin(), Tmp1.second.end());	//为该商家来单时刻排序

		int PerT = 0, Count = 0;
		for (auto& Tmp2 : Tmp1.second)	//遍历所有单
		{
			int TGap = Tmp2 - PerT;	//计算上一单到这一单的时间差
			PerT = Tmp2;	//记录这一单的时间

			Count = max(0, Count - (TGap == 0 ? 1 : TGap) + 1);	//减去时间差,最后+1是因为Tmp2时刻有单无需减少,再特殊处理当TGap == 0的情况
			if (Count <= 3 && PList.count(Tmp1.first)) { PList.erase(Tmp1.first); }
			Count += 2;	
			if (Count > 5 && !PList.count(Tmp1.first)) { PList[Tmp1.first]++; }
		}

		if (PerT < InT) { Count = max(0, Count - (InT - PerT)); }	//最后计算到最后时刻的有些指数
		if (Count <= 3 && PList.count(Tmp1.first)) { PList.erase(Tmp1.first); }
		else if (Count > 5 && !PList.count(Tmp1.first)) { PList[Tmp1.first]++; }
	}

	cout << PList.size();

	return 0;
}
### 蓝桥杯 外卖优先级 Java 实现 解题思路 #### 1. 题目分析 题目描述了一种动态变化的优先级机制,其中每家外卖优先级随时间和订单数量的变化而调整。具体规则如下: - 如果某外卖在某一时间单位内无订单,则其优先级减少 1,但不会低于 0[^1]。 - 若该外卖在此时间内有订单,则优先级增加 2,对于每一单均如此处理[^2]。 因此,解题的核心在于如何高效地计算各外卖在指定时间 `t` 的最终优先级,同时避免因数据规模较大而导致的时间或空间复杂度过高问题[^3]。 --- #### 2. 数据结构设计 为了满足性能需求并简化逻辑,可以采用以下两种主要的数据结构: ##### (1) 哈希表 (`HashMap`) 哈希表用于存储每个时间节点上发生订单的外卖集合。键表示某个特定时间点 `t`,值是一个列表,保存在该时间点下单的所有外卖编号[^4]。 ```java Map<Integer, List<Integer>> orderMap = new HashMap<>(); ``` ##### (2) 数组 定义一个长度为 `N` 的整型数组,用来记录每一外卖的当前优先级状态。初始化时,所有外卖优先级均为 0。 ```java int[] priorityArray = new int[N]; Arrays.fill(priorityArray, 0); ``` --- #### 3. 算法流程 以下是基于上述数据结构的具体实现步骤: ##### (1) 输入解析 读取输入数据,构建 `orderMap` 表示各个时间段内的订单情况。假设输入格式为多行数据,每行为三个整数:`time`, `store_id`, 和 `orders_count`,分别对应时间、外卖编号以及此时间下的订单量。 ```java for (int i = 0; i < M; i++) { String[] line = br.readLine().split(" "); int time = Integer.parseInt(line[0]); int storeId = Integer.parseInt(line[1]); if (!orderMap.containsKey(time)) { orderMap.put(time, new ArrayList<>()); } orderMap.get(time).add(storeId); } ``` ##### (2) 动态更新优先级 遍历从 `0` 到目标时间 `T` 的每一个时间点,在每次迭代中完成两部分操作: - **降低未接单铺的优先级**:检查哪些铺在过去一段时间里没有任何新订单,并对其执行 `-1` 操作; - **提升已接单铺的优先级**:依据当前时间点上的订单信息,对相应铺实施 `+2 * orders_count` 更新。 注意优化效率,仅针对实际存在活动的时间节点进行详细运算即可。 ```java Set<Integer> activeStores = new HashSet<>(); // 初始化活跃铺为空集 activeStores.clear(); for (int currentTime = 0; currentTime <= T; currentTime++) { // 对于非活跃铺降权 for (int s = 1; s <= N; s++) { if (!activeStores.contains(s)) { priorityArray[s - 1] = Math.max(0, priorityArray[s - 1] - 1); } else { activeStores.remove(s); // 清除标记以便下一轮重新评估 } } // 当前时刻若有新增订单则提权 if (orderMap.containsKey(currentTime)) { List<Integer> storesWithOrders = orderMap.get(currentTime); for (Integer store : storesWithOrders) { priorityArray[store - 1] += 2; activeStores.add(store); // 添加至活跃铺集合以防重复扣分 } } } ``` --- #### 4. 输出结果 最后打印出所有外卖在给定结束时间后的最终优先级数值。 ```java StringBuilder sb = new StringBuilder(); for (int p : priorityArray) { sb.append(p).append("\n"); } System.out.print(sb.toString()); ``` --- ### 总结 以上方法利用了高效的哈希映射和简单的线性扫描技术来解决大规模数据场景中的动态优先级管理问题。它不仅能够有效控制运行时间成本,还兼顾了内存使用的合理性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值