基本思路:设置队列数组qInside[i]用来存放第i个窗口前对应的等待客户,队列qBehind用来存放黄线以外的等待客户。然后访问每个窗口前等待队列的队首元素,即customer编号。找出这些顾客中交易时间的最小值,假设此时对应的窗口编号为j,则弹出qInside[j]的队首元素,此时若qBehind非空,则将其队首元素压入qInside[j]。最后再对每个窗口前的等待队列进行一次遍历,将上次遍历过程中所有未弹出的队首元素(即顾客编号)对应的交易时间减去被弹出的队首元素cus对应的交易时间,即timePro[ ] -= timePro[cus],并令总的计时器Time += timePro[j],同时记下客户的交易结束时刻timeEnd[cus] = Time。重复以上步骤,即可求出每个顾客的交易结束时刻。
ps:题目中要求下午五点之前才能开始进行交易,也就是说交易结束的时间可以在五点之后。
提交代码:
#include <iostream>
#include <queue>
#include <cstdio>
using namespace std;
int n, m, k, q;
int timePro[2010], processTime[2010]; //每个顾客的交易时长
int timeEnd[2010]; //每个顾客的结束时刻
int Time = 0; //窗口交易的总时长
int main()
{
//freopen("in_1014.txt", "r", stdin);
cin >> n >> m >> k >> q;
for(int i = 1; i <= k; i++)
{
cin >> timePro[i];
processTime[i] = timePro[i]; //生成一个副本,便于后面修改交易时间
}
queue<int> qInside[21]; //n个窗口的等待队列
queue<int> qBehind; //黄线以后的等待队列
for(int i = 1; i <= k; i++) //将所有顾客放入相应的等待队列
{
if(i > n * m) qBehind.push(i);
else
{
int j = (i-1) % n;
qInside[j].push(i);
}
}
bool isEmpty = false; //判断所有窗口前的等待队列是否都为空
while(!isEmpty)
{
int customerID, minTimePro = 10000, windowID;
for(int i = 0; i < n; i++)
{
if(!qInside[i].empty())
{
int front = qInside[i].front();
if(timePro[front] < minTimePro)
{
minTimePro = timePro[front];
windowID = i;
customerID = front;
}
}
}
Time += minTimePro;
timeEnd[customerID] = Time;
qInside[windowID].pop();
for(int i = 0; i < n; i++)
{
if(!qInside[i].empty())
{
if(i != windowID)
{
int front = qInside[i].front();
timePro[front] -= minTimePro;
}
}
}
if(!qBehind.empty())
{
int front = qBehind.front();
qBehind.pop();
qInside[windowID].push(front);
}
isEmpty = true;
for(int i = 0; i < n; i++)
if(!qInside[i].empty()) isEmpty = false;
}
for(int i = 0; i < q; i++)
{
int cus;
cin >> cus;
if(timeEnd[cus] - processTime[cus] < 60 * 9)
{
int hour = 8 + timeEnd[cus] / 60;
int minute = timeEnd[cus] % 60;
printf("%02d:%02d\n", hour, minute);
}
else printf("Sorry\n");
}
}
最后,分享一下别人的思路,实现起来更容易。基本思路就是对每一个服务窗口都设置一个交易的总时间,每一次入队都计算出改顾客的交易结束时刻并更新对应窗口的交易总时间。重复上述步骤,直至达到窗口前的最大等待容量或者所有的顾客都已进入等待队列为止。若最大等待容量小于顾客数,则找出各个窗口前的等待队列中队首顾客离开时间的最小值,并将其出队同时将剩下的顾客加入该等待队列,则该顾客的离开时刻也就是当前窗口的总交易时刻加上改顾客的交易时间,重复这个步骤,直到所有的顾客都已经加入相应窗口前的等待队列时,算法终止。
代码如下:
#include <iostream>
#include <queue>
#include <cstdio>
using namespace std;
int n, m, k, q;
int timePro[2010]; //每个顾客的交易时长
int timeEnd[2010]; //每个顾客的结束时刻
int timeWin[21] = {0}; //每个窗口交易的总时长
int main()
{
//freopen("in_1014.txt", "r", stdin);
cin >> n >> m >> k >> q;
for(int i = 0; i < k; i++)
cin >> timePro[i];
queue<int> que[21]; //n个窗口的等待队列
int top = 0;
for(int i = 0; top < n * m && top < k; top++) //将最大容量内的顾客放入相应的等待队列
{
que[i].push(top);
timeEnd[top] = timeWin[i] + timePro[top];
timeWin[i] = timeEnd[top];
i = (i + 1) % n;
}
for(; top < k; top++) //将超出最大容量的顾客依次压入相应窗口的等待队列
{
int min_wait = 10000, windowID;
for(int i = 0; i < n; i++)
{
int cus = que[i].front();
if(timeEnd[cus] < min_wait)
{
min_wait = timeEnd[cus];
windowID = i;
}
}
que[windowID].pop();
que[windowID].push(top);
timeEnd[top] = timeWin[windowID] + timePro[top];
timeWin[windowID] = timeEnd[top];
}
for(int i = 0; i < q; i++)
{
int cus;
cin >> cus;
cus--;
if(timeEnd[cus] - timePro[cus] < 60 * 9)
{
int hour = 8 + timeEnd[cus] / 60;
int minute = timeEnd[cus] % 60;
printf("%02d:%02d\n", hour, minute);
}
else printf("Sorry\n");
}
}