首页 > 技术文章 > 第十届蓝桥杯省赛JavaB组——第七题外卖店优先级

pengsay 2021-03-15 21:34 原文

题目:

试题 G: 外卖店优先级
时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分
【问题描述】
“饱了么”外卖系统中维护着 N 家外卖店,编号 1 ∼ N。每家外卖店都有
一个优先级,初始时 (0 时刻) 优先级都为 0。
每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减
0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。
如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;如果
优先级小于等于 3,则会被清除出优先缓存。
给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优
先缓存中。
【输入格式】
第一行包含 3 个整数 N、M 和 T。
以下 M 行每行包含两个整数 ts 和 id,表示 ts 时刻编号 id 的外卖店收到
一个订单。
【输出格式】
输出一个整数代表答案。
【样例输入】
2 6 6
1 1
5 2
3 1
6 2
2 1
6 2
【样例输出】
1
【样例解释】
6 时刻时,1 号店优先级降到 3,被移除出优先缓存;2 号店优先级升到 6,
加入优先缓存。所以是有 1 家店 (2 号) 在优先缓存中。
【评测用例规模与约定】
对于 80% 的评测用例,1 ≤ N, M, T ≤ 10000。
对于所有评测用例,1 ≤ N, M, T ≤ 100000,1 ≤ ts ≤ T,1 ≤ id ≤ N。

分析思路:

思路:经观察发现,如果将优先级的加和减放在一起判断执行,可能会造成结果的不正确性,所以这里我
们把优先级的加和减分开来完成

步骤:

1、在接收用户输入的订单时,就作如下操作:将每时刻时,有哪些外卖店铺接收到多少订单的信息
都用Map集合先存储起来,供后面使用,这里我们需要的不仅仅是一个Map集合,为了对应每个时刻,
我们创建一个Map类型的数组,用数组是为了很方便的检索到指定时刻对应的哪些外卖店铺收到的订
单情况。
2、再通过一个循环遍历所有时刻,将每个时刻接收到订单的外卖店铺的优先级都计算一下并将其保存在
priority数组中,这中间我们每次还需要判断优先级是否满足进入优先缓冲中或者不满足并用cache数
组的下标来标志哪些店铺已经在优先缓冲中,哪些不下(在为1,不在为0),而且在这次循环另外还能将
每个外卖店铺的最后一个接收订单的时刻统计出来,并将其存储到last数组中。这样一来,在结束这次循
环之后,就等于将所有订单都处理完了,那么接下来就只剩下时间在推移,对应着每个外卖店铺的优先级
都要每时刻-1,直到t时刻结束。也就是最后可以再通过一次循环即可统计出每个店铺最终在t时刻的优先
级。
3、最后我们只需遍历一次cache数组,循环中累加已经在优先缓冲中的所有外卖店铺

 

暴力代码:

 1 import java.util.Scanner;
 2 
 3 /*试题 G: 外卖店优先级
 4 时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分
 5 
 6 大佬的代码:
 7 
 8 暴力分析(80%):
 9 
10 直接模拟运算过程,
11 创建一个二维数组,横坐标为店的 id,纵坐标为时间 ti,
12 每获取一个订单,就在(id,ti)的位置+1;
13 最后遍历一下二维数组即可。
14 时间复杂度O(n*t)
15  * */
16 public class G暴力 {
17     public static void main(String[] args) {
18         Scanner sc = new Scanner(System.in);
19         int n = sc.nextInt(), m = sc.nextInt(), t = sc.nextInt();
20 
21         // 辅助数组,i表示i时刻,j表示j号外卖店 arr[i][j] = val 则是指在i时刻j号外卖店收到的订单个数
22         int arr[][] = new int[t + 1][n + 1];
23 
24         for (int i = 0; i < m; i++) {
25             arr[sc.nextInt()][sc.nextInt()]++;
26         }
27         int prio[] = new int[n + 1];
28 
29         for (int i = 1; i < t + 1; i++) {
30             for (int j = 1; j < n + 1; j++) {
31                 // 查看第i时刻第j个店有没有订单,如果有,就在该店的第i - 1时刻的基础之上再累加,注意:只要有了,
32                 // 此时arr[i - 1][j]已经考察过了,所以其中存储的就是i - 1时刻该店的优先等级
33                 /*
34                     通过某时刻某家店的订单个数,来算出某时刻某家的的优先等级
35                  */
36                 if (arr[i][j] > 0) {
37                     arr[i][j] = arr[i - 1][j] + arr[i][j] * 2;
38                     if (arr[i][j] > 5)
39                         prio[j] = 1;
40                 } else {
41                     // 如果此时第i时刻第j个店没有订单,则查看该店的第i - 1的优先等级
42                     if (arr[i - 1][j] > 0) {
43                         /*
44                             解释说明:
45                              当前时刻i的前一个时刻i - 1,arr[i - 1][j] 代表的是i - 1时刻的优先等级,因为只要考察
46                              过后的数组都是存储了那个时刻那家店的优先等级(再次强调,一定是考察过后)
47                              而返回来说,没有考察过的或者正在考察的都是存储的当前时刻该店所收到的订单数量
48                          */
49                         arr[i][j] = arr[i - 1][j] - 1;
50                         if (arr[i][j] < 4)
51                             prio[j] = 0;
52                     }
53                 }
54             }
55         }
56         int ans = 0;
57         for (int i = 0; i < prio.length; i++) {
58             ans += prio[i];
59         }
60         System.out.println(ans);
61     }
62 }

AC代码:

  1 public class GAC {
  2 
  3     /**
  4      * 店铺个数
  5      */
  6     private static int N;
  7 
  8     /**
  9      * 总的订单个数
 10      */
 11     private static int M;
 12 
 13     /**
 14      * 时间
 15      */
 16     private static int T;
 17 
 18     /**
 19      * 优先缓冲,这里用数组中存储的数字0、1来标志是否存在优先缓冲中
 20      */
 21     private static int cache[] = new int[N + 1];
 22 
 23     /**
 24      * map类型数组,用于存储每个时刻每个店铺接收到的订单情况,下标代表某时刻
 25      */
 26     private static Map<Integer, Integer>[] map;
 27 
 28     /**
 29      * last集合,用于存储每个外卖店铺最后一次接收订单的时刻
 30      */
 31     private static int[] last;
 32 
 33     /**
 34      * priority数组,用于保存每个外卖店铺对应的优先级,下标i代表i号店铺
 35      */
 36     private static int[] priority;
 37 
 38     public static void main(String[] args) {
 39         Scanner input = new Scanner(System.in);
 40         N = input.nextInt();
 41         M = input.nextInt();
 42         T = input.nextInt();
 43         // 初始化数组
 44         map = new HashMap[T + 1];
 45         last = new int[N + 1];
 46         priority = new int[N + 1];
 47         cache = new int[N + 1];
 48 
 49         // 初始化map数组中的所有集合元素
 50         for (int i = 0; i < T + 1; i++) {
 51             map[i] = new HashMap<>();
 52         }
 53 
 54         for (int i = 0; i < M; i++) {
 55             int ts = input.nextInt();
 56             int id = input.nextInt();
 57             if (map[ts].containsKey(id)) {
 58                 // 说明当前时刻已经有该店铺收到过订单了,可以直接在此基础上+1
 59                 map[ts].put(id, map[ts].get(id) + 1);
 60             } else {
 61                 // 表示该用户在此时刻还没有收到过订单,则初始为1
 62                 map[ts].put(id, 1);
 63             }
 64         }
 65         input.close();
 66 
 67         // 时间推移
 68         for (int i = 0; i < T + 1; i++) {
 69             for (int id : map[i].keySet()) {
 70                 // 计算此时的优先级,不考虑当前正在遍历的时刻,只考虑最后一次接收到订单的时刻之后,当前时刻之前这个范围
 71                 // 每过1个时刻,优先级-1,这里要跟0比大家应该不觉得有疑问吧,仔细读懂题的人都知道
 72                 priority[id] = Math.max(priority[id] - (i - last[id] - 1), 0);
 73                 // 考察店铺此时刻接收的订单情况
 74                 priority[id] += (map[i].get(id) * 2);
 75                 // 接下来就是对优先级是否符合进入或离开优先缓冲条件的判断
 76                 if (priority[id] > 5 && cache[id] == 0) {
 77                     cache[id] = 1;
 78                 } else if (priority[id] <= 3 && cache[id] == 1) {
 79                     cache[id] = 0;
 80                 }
 81                 // 不要忘了,修改最后一次接收订单的时刻
 82                 last[id] = i;
 83             }
 84         }
 85 
 86         // 整体来算一下每个店铺从最后一次接收订单之后到t时刻这段时间的优先级
 87         // 考察所有店铺
 88         for (int i = 0; i < N + 1; i++) {
 89             /*
 90                 考虑最后一次接收到订单的时刻之后,t时刻(t时刻也包含在内,因
 91                 为最后一次接收订单的时刻已经处理了,所有这里不需要再考虑)这
 92                 个范围
 93              */
 94 
 95             priority[i] -= (T - last[i]);
 96             // 接下来就是对优先级是否符合进入或离开优先缓冲条件的判断
 97             if (priority[i] > 5 && cache[i] == 0) {
 98                 cache[i] = 1;
 99             } else if (priority[i] <= 3 && cache[i] == 1) {
100                 cache[i] = 0;
101             }
102         }
103 
104         // 统计此时在优先缓冲中的店铺有多少个
105         int ans = 0;
106         for (int i = 0; i < N + 1; i++) {
107             ans += cache[i];
108         }
109         System.out.println(ans);
110     }
111 }

 

推荐阅读