蓝桥杯-外卖店优先级

蓝桥杯-外卖店优先级

1.题目介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.一般想法

(可以着重看优化做法)

首先存储i时刻,j号店,有多少订单;
然后依次遍历每一个时刻的每一家店,
判断哪些店有订单,有订单的话,优先级就加上2*订单数;
其次,判断店铺的优先级是否>5,是的话就进入优先缓存;
如果店铺的优先级<=3,就退出优先缓存;
那些没有订单的店,优先级就-1,注意要保证优先级一直>=0;
最后,遍历所有店铺,看有多少店铺在优先缓存中,输出答案;

但是,根据题目限制,这种做法在数据较大时会超时,拿不到所有分数

#include <bits/stdc++.h>
using namespace std;
int dd[10010][10010];//存储i时刻,j号店,有多少订单;
bool st[10010];//存储j号店是否在优先缓存中
int score[10010];//存储j号店的优先级
int main(){
    int N,M,T;
    cin>>N>>M>>T;
    while(M--)
    {
        int ts,id;
        cin>>ts>>id;
        dd[ts][id]++;
    }
    for(int i=1;i<=T;i++)//遍历每一个时刻的每一家店
        for(int j=1;j<=N;j++)
            {
            if(dd[i][j]>0)//如果i时刻j号店有订单
                {
                    score[j]+=2*dd[i][j];//每有一单优先级加 2,直接2*订单数
                }
                else//如果外卖店没有订单,则优先级会减少 1,最低减到 0
                {
                    if(score[j]-1>=0)score[j]--;
                }
                if(score[j]>5)st[j]=true;
                if(score[j]<=3)st[j]=false;
            }
    int res=0;
    for(int i=1;i<=N;i++)//遍历每一家店,如果在优先缓存中,res+1,否则res+0;
    res+=st[i];

    cout<<res;
    return 0;

}

不过往往考试比赛中更有现实实际价值。

3.优化做法

我们主要处理有订单的信息,对于连续的没有订单的情况不再逐一处理,而是根据有订单的时间节点一并进行处理。

  1. 输入m个订单信息,排序(时间t为第一优先级,订单id为第二优先级)
  2. for遍历订单信息(此时订单已经是按照时间顺序排的)
  3. 假设当前订单为第i个,循环判断后面有没有相同的订单(即t和id相等)。(有的话一定连续)
  4. 到第j个时订单不相同,此时相同订单的数量为cnt=j−i
  5. 下一次for循环从j处开始遍历
  6. 记录此时的t和id, 计算id的优先权,有两部分

在这里插入图片描述

7.解释上面那个,因为此时这几个相同的订单都计算过了不需要再计算了,所以下一次循环要从j开始
8. 循环最后上一次拿到订单的时间last[id]更新为t
9. 如果最后一个订单时刻为T,则没问题。如果不是T,那么最后一个拿到订单时刻到T时刻的这部分减法需要手动计算,即减去最后一个订单时刻与T的差值。换而言之,如果上一个拿到订单的时间last[id]小于T,则优先权 减去 T−last[id]。注意这里不减1,因为T时刻也没订单。如果小于等于3,更新优先缓存
Java代码:

下面的样例代码也有对应注释便于理解
score[i]存第i店铺分数的;
last[i]第i个店铺上一次有订单的情况;
st[i]第i个店铺是否在优先缓存中

#include<cstdio>
#include<string>
#include<iostream>
#include<algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int,int>PII;

const int N=100010;

int n,m,T;//n店铺数量;m订单数量;T时间
int score[N],last[N];
bool st[N];

PII order[N];//所有的订单,存 时间 店铺名

int main()
{
    scanf("%d%d%d",&n,&m,&T);
    for(int i=0;i<m;i++)scanf("%d%d",&order[i].x,&order[i].y);
    sort(order,order+m);//pair自带的排序,双关键词比较
    //按照时间顺序排序;时间相同
    
    for(int i=0;i<m;)//有订单才有信息
    {
        int j=i;
        while(j<m&&order[j]==order[i])j++;//处理相同一批(即同一时刻相同店铺有订单),相同则统计
        int t=order[i].x,id=order[i].y;//t,id记录的是这一时刻这一店铺有订单的情况
        int cnt=j-i;//找了一个j=i+1;两个j=i+2;直接相减即可
        i=j;//在j的基础上往后继续寻找
        
        
        //这里处理的是中间没订单的情况
        score[id]-=t-last[id]-1;//与该店铺上一次有订单的时刻相比,比如2时刻到5时刻之间,3 4时刻没有那么减去2即可
        if(score[id]<0)score[id]=0;
        if(score[id]<=3)st[id]=false;//这里处理的是t时刻之前的信息
        
        
        //这里处理的是t时刻有订单的情况
        score[id]+=cnt*2;
        if(score[id]>5)st[id]=true;//处理t时刻的信息
        
        last[id]=t;//表示这一次id店铺有订单的情况,对于之后也就是上一次id店铺有订单的情况
    }
    
    for(int i=1;i<=n;i++)
        if(last[i]<T)//之后i店铺确实没订单了
        {
            score[i]-=T-last[i];//这本身也包括T时刻
            if(score[i]<=3)st[i]=false;
        }
        
        int res=0;
        for(int i=1;i<=n;i++)res+=st[i];
        
        printf("%d\n",res);
        
        return 0;
}



  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值