数据结构——银行排队问题之单队列多窗口加VIP服务

题目大意:有很多个服务窗口,有一个窗口是VIP窗口,如果这个窗口有空闲,并且排队等待的人里有VIP,那么VIP先去这个窗口办理业务(SORRY,充钱就是了不起),如果果有多个窗口可以选择,顾客会优先选择窗口编号小的。

题目链接:https://pintia.cn/problem-sets/1042354461223579648/problems/1042355242509160453#p-6

在网上看到很多博客评论这道题很恶心,在这里也跟风一下,这道题确实很恶心。 改了很多次思路,最终AC。

 

这道题,推荐自己疯狂尝试后,在看看题解是如何给出的,这道题会帮助你踩出很多的思维漏洞,额。。。说到思维漏洞,还有题意,注意题目中所给的窗口的编号是从0开始的(心粗的一批)。

 

现在这里说一下错思路的最终版本:

在这道题之前有一个单队列多窗口问题如果不知道,点这里,保持那个问题的整体框架不变,对VIP窗口进行特别的判断,当一个用户的选择是VIP窗口时,这时候就需要判断,队列中是否含有VIP会员,如果有的话,去找次的最快窗口,然后输出。

代码实现:

#include <bits/stdc++.h>

using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1000+10;

struct node
{
    int st;
    int work;
    int vip;
    bool operator < (const node&s ) const
    {
        return st<s.st||(st==s.st&&vip>s.vip);
    }
};

struct nodes
{
    int num;
    int endtime;
    nodes() {num=0; endtime=0;}
};

node que[maxn];
nodes w[maxn];
bool used[maxn];

int main()
{
    int n; scanf("%d",&n);

    for(int i=0;i<n;i++)
    {
        scanf("%d %d %d",&que[i].st,&que[i].work,&que[i].vip);
        que[i].work = que[i].work>=60 ? 60: que[i].work;
    }
    sort(que,que+n);

//    for(int i=0;i<n;i++)
//    {
//        cout<<"输出中间值   "<<que[i].st<<"     "<<que[i].work<<"     "<<que[i].vip<<endl;
//    }
    int k,vipw; scanf("%d %d",&k,&vipw);
    vipw++;


    int max_w=0,max_f=0,sumw=0;

    //cout<<"检测"<<endl;
    for(int i=0; i<n; i++)
    {
        if(used[i]) continue;

        bool flag=false;

        int fw=INF,fn=INF;

        for(int j=1; j<=k; j++)
        {
            if(w[j].endtime<=que[i].st)
            {
                used[i]=true;

                w[j].num++;

                w[j].endtime=que[i].st+que[i].work;

                flag=true;

                //cout<<"输出最后窗口    "<<fn<<"   "<<i<<endl;
                break;
            }

            if(fw>(w[j].endtime-que[i].st))
            {
                fw=w[j].endtime-que[i].st;
                fn=j;
            }

        }

       // cout<<"输出过程值           "<<i<<"   "<<fn<<"    "<<flag<<endl;

        if(flag) continue;

        if(fn==1&&que[i].vip==0)
        {

            bool judge=false;
            int pos=0;

            for(int j=i+1;j<n;j++)
            {
                if(i+1<n&&que[j].vip==1&&que[j].st<=w[fn].endtime)
                {
                    judge=true;
                    pos=j;
                    //cout<<"输出搜索位置的值    "<<j<<endl;
                    break;
                }
            }

            if(judge)
            {

                int fw1=INF,fn1=INF;
                for(int j=1; j<=k; j++)
                {
                    if(j==fn) continue;
                    if(fw1>w[j].endtime-que[i].st)
                    {
                        fw1=w[j].endtime-que[i].st;
                        fn1=j;
                    }

                }

                used[pos]=true;
                used[i]=true;

                w[fn].num++;
                w[fn1].num++;

                max_w=max(max_w,w[fn].endtime-que[pos].st);
                max_w=max(max_w,w[fn1].endtime-que[i].st);

                sumw+=(w[fn].endtime-que[pos].st+w[fn1].endtime-que[i].st);

                w[fn].endtime=w[fn].endtime+que[pos].work;
                w[fn1].endtime=w[fn1].endtime+que[i].work;

                //cout<<"gg2      "<<max_w<<endl;

                 //cout<<"输出最后窗口    "<<fn<<"   "<<i<<endl;

            }
            else
            {
                used[i]=true;

                w[fn].num++;

                max_w=max(max_w,w[fn].endtime-que[i].st);

                sumw+=(w[fn].endtime-que[i].st);

                w[fn].endtime=w[fn].endtime+que[i].work;

                //cout<<"gg2      "<<max_w<<endl;
                //cout<<"输出最后窗口    "<<fn<<"   "<<i<<endl;


            }
        }
        else
        {
            used[i]=true;

            max_w=max(max_w,w[fn].endtime-que[i].st);

            w[fn].num++;

            sumw+=(w[fn].endtime-que[i].st);

            w[fn].endtime=w[fn].endtime+que[i].work;

            //cout<<"gg2      "<<max_w<<endl;
            //cout<<"输出最后窗口    "<<fn<<"   "<<i<<endl;


        }


    }

    for(int i=1;i<=k;i++)
        max_f=max(max_f,w[i].endtime);


    //cout<<"输出总的等待时间   "<<sumw<<endl;

    printf("%.1f %d %d\n",sumw*1.0/n,max_w,max_f);


    int isfirst=1;
    for(int i=1;i<k;i++)
    {
        if(!isfirst) printf(" ");
        if(i==vipw)
        {
             printf("%d %d",w[1].num,w[i+1].num);
        }
        else printf("%d",w[i+1].num);

        isfirst=false;
    }


    return 0;
}

但是提交玩成后只能获得25分,然后就开始寻找自己的错误,最后花了两个小时,才滤出了自己的漏洞,这应该也是这道题最恶心的地方。

当一个普通用户选择VIP窗口时,我们执行的操作是让她去寻找另一个次快的窗口,但是这里有个问题,就是那个插队的VIP办理业务非常快,你仍然要在那个VIP窗口排队,然后需要再一次的判断队列中是否有VIP,如果下一个VIP办理业务依旧很快,你仍然在VIP窗口排队,你需要再次考虑。。。。。。如此的循环下去,(PS:这个是一个简单的For循环能够解决,可以自己动手试一试)

 

然后就是正确的思路,暴力枚举时间流逝一i秒一秒的判断,因为最多有1000个人,而且没人办理业务的时间最多是60S,所以总时间最多就是60000,时间复杂度很小。

 

下面给出AC代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn=2000;
const int INF=0x3f3f3f3f;



struct node
{
    int st,et,vip;
};



node que[maxn];
int wd[maxn];
bool used[maxn],te[11][maxn*60];

int main()
{
    int n;  scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d %d %d",&que[i].st,&que[i].et,&que[i].vip);
        que[i].et= que[i].et>=60 ? 60 : que[i].et;
    }

    int k,vipw; scanf("%d %d",&k,&vipw);

    int cnt=n,sumw=0,max_w=0,max_f=0;
    for(int t=0;cnt;t++)
    {

        if(te[vipw][t]==false)
        {

            for(int i=0;i<n;i++)
            {
                if(used[i]||!que[i].vip) continue;
                if(que[i].st>t) break;

                wd[vipw]++;

                max_w=max(max_w,t-que[i].st);

                max_f=max(max_f,t+que[i].et);

                sumw+=(t-que[i].st);

                cnt--;

                used[i]=true;


                for(int j=0;j<que[i].et;j++) te[vipw][t+j]=true;


                break;
            }
        }

        for(int i=0;i<k;i++)
        {
            if(te[i][t]==false)
            {
                for(int j=0;j<n;j++)
                {
                    if(used[j]) continue;
                    if(que[j].st>t) break;

                    wd[i]++;

                    max_w=max(max_w,t-que[j].st);

                    sumw+=(t-que[j].st);

                    cnt--;

                    used[j]=true;

                     max_f=max(max_f,t+que[j].et);

                    for(int h=0;h<que[j].et;h++) te[i][t+h]=true;

                    break;
                }
            }
        }
    }

    printf("%.1f %d %d\n",sumw*1.0/n,max_w,max_f);

    for(int i=0;i<k;i++)
    {
        if(i) printf(" ");
        printf("%d",wd[i]);
    }
    return 0;
}

 

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 单队列多窗口VIP服务是一种银行排队管理方式,它解决了在银行排队时的等待问题。在这种方式中,顾客只需排在一个队列中,但有多个窗口可供办理业务。VIP客户可以使用专门的VIP窗口进行服务。这样可以有效地减少顾客的等待时间,提高服务效率。 ### 回答2: 在银行的日常营运中,排队问题一直是一个非常棘手的问题。为了解决排队问题,现在许多银行采取单队列多窗口vip服务的模式来服务客户。这种模式的主要优点在于: 1. 窗口数量增多:采用多窗口服务,客户可以选择任意一个窗口进行业务办理,因此客户办理业务的速度大大增,等待时间减少。 2. 排队相对公平:单队列可以让每个客户都先后按照时间顺序进入等待状态,从而避免了“抢号”、“肘挤肘”等问题。 3. VIP服务:针对忙碌的客户和要办理复杂业务的客户,银行可以提供VIP服务,使排队问题得到进一步缓解,提高了银行的服务品质。 总的来说,采用单队列多窗口vip服务的方式可以从客户的角度出发,解决排队问题,提高客户体验;从银行的角度出发,优化窗口资源利用,提高业务量。如果一家银行能够善用这种服务模式,相信在服务质量和经济效益方面都会获得不错的收益。 ### 回答3: 银行排队问题是一个常见的实际问题,在每个银行的营业厅内经常会看到顾客排队等待办理业务的场景。为了解决银行排队问题,银行经常采用单队列多窗口VIP服务的方式。 单队列多窗口的方式是指在银行的营业厅内,设置一个单独的队列,所有需要办理业务的顾客都需要先排在该队列中,而不是在各个柜台前各自排队。在该队列前设置多个窗口,每个窗口都可以为队列中的顾客提供服务。这样做可以有效避免因为某一个柜台办理业务时间过长而导致其他的顾客需要等待过久的时间。 在单队列多窗口的基础上,部分银行还会增设VIP服务VIP服务是指为了提升银行高端客户的体验而设置的一种服务。顾客可以通过一定条件获得VIP服务,如拥有高额存款等。银行会专门为VIP客户设置一些额外的窗口,以便为其提供更为优质的服务。在单队列多窗口结构中,VIP窗口可以与普通窗口一样为VIP客户服务,使得其等待时间更短。 采用单队列多窗口VIP服务有以下优点: 一、可以平衡各窗口的负荷,降低普通柜员的工作压力。 二、可以减少客户等待时间,提升服务效率。 三、增设VIP服务可以提升高端客户的体验,同时也能带来实质性的业务贡献。 综上所述,采用单队列多窗口VIP服务是解决银行排队问题的一种有效方案,可以为银行提升服务质量、减少客户等待时间、提升客户满意度、实现营业效益的多重目标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值