1. 程式人生 > >資料結構——銀行排隊問題之單佇列多視窗加VIP服務

資料結構——銀行排隊問題之單佇列多視窗加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;
}