我的数据结构与算法题目集代码仓:https://github.com/617076674/Data-structure-and-algorithm-topic-set
原题链接:https://pintia.cn/problem-sets/15/problems/895
题目描述:
思路:模拟银行排队问题
(1)用一个unordered_map<string, int>类型的变量friendMap记录拥有朋友圈的人名对应的朋友圈编号。
(2)用一个unordered_map<string, int>类型的变量customerId记录每个人名的到达顺序。
(3)用一个bool型的visited[]数组标记第i个到达的人是否被服务过。
(4)用一个vector<string>类型的数组friends[]存储朋友圈编号为i的朋友名。
(5)用一个int型变量window存储窗口能接受下一次服务的最早时间。
注意点:
(1)对于朋友圈中的人,如果其到达时间迟于上一个朋友处理完毕的时间,即窗口时间,则无法插队。
(2)如果在friendMap中没有找到某人名,说明这个人不属于任何朋友圈,单独处理这个人就行了。
(3)对于每个朋友圈中的人名,都需要按照到达顺序进行排序。
(4)如果客户的到达时间大于window,需要将window更新为该客户的到达时间加上该客户的处理时间。
时间复杂度和空间复杂度均与输入的朋友圈组成有关。
给出本题各个测试点的测试数据:
序号 | 输入 | 输出 | 说明 |
0 | 6 0 JIM 0 20 BOB 0 15 ANN 0 30 AMY 0 2 ZOE 1 61 JOE 3 10 |
JIM BOB ANN AMY ZOE JOE 51.7 |
没有朋友圈,即无人夹塞。 ZOE的处理时间超过了60分钟,按60分钟计算。 |
1 | 6 2 3 ANN BOB JOE 2 JIM ZOE JIM 0 20 BOB 0 15 ANN 0 30 AMY 0 2 ZOE 1 61 JOE 3 10 |
JIM ZOE BOB ANN JOE AMY 75.2 |
ANN、JOE和ZOE夹塞,导致没有朋友的AMY一直排在最后。 |
2 | 6 2 3 ANN BOB JOE 2 JIM ZOE JIM 0 20 BOB 0 15 AMY 0 2 ZOE 21 61 ANN 35 30 JOE 45 10 |
JIM BOB ANN JOE AMY ZOE 28.5 |
ANN刚好赶上BOB处理完自己的事务,不用等待就夹塞;而ZOE虽然跟JIM是朋友,但是他到达的时候JIM已经走了,于是只好排队。 |
3 | 6 2 3 ANN BOB JOE 2 JIM ZOE JIM 0 20 BOB 22 15 AMY 22 2 ZOE 22 61 ANN 35 30 JOE 45 10 |
JIM BOB ANN JOE AMY ZOE 22.7 |
窗口有完全空闲的一段时间,等待BOB到来。 |
4 | 2 1 2 AAA ZZZ AAA 1 20 ZZZ 2 10 |
AAA ZZZ 9.5 |
边界测试,只有2位顾客,且名字取到最大、最小值。 |
5 | 1 0 ANN 1 20 |
ANN 0.0 |
边界测试:只有1位顾客。 |
6 | 随机大数据,包含10000名顾客,其中100个朋友圈,每个圈子有100名朋友。 | 略 | 边界测试:上界测试。 |
C++代码:
#include<iostream>
#include<cstring>
#include<unordered_map>
#include<vector>
#include<algorithm>
using namespace std;
struct customer { //定义顾客结构体
char name[4];
int arriveTime, processTime;
};
int N, M;
unordered_map<string, int> friendMap, customerId; //friendMap存储每个人所属的朋友圈编号,customerId存储每个人名的到达顺序
bool visited[10000]; //visited[]数组标记第i个到达的人是否已经被处理过
vector<string> friends[100], result; //friends[i]存储朋友圈编号为i的朋友名,result存储结果
bool cmp(string s1, string s2);
int main() {
scanf("%d %d", &N, &M);
fill(visited, visited + N, false);
for(int i = 0; i < M; i++) {
int L;
scanf("%d", &L);
for(int j = 0; j < L; j++) {
char name[4];
scanf("%s", name);
friendMap[name] = i;
friends[i].push_back(name);
}
}
customer customers[N];
for(int i = 0; i < N; i++) {
char name[4];
scanf("%s %d %d", name, &customers[i].arriveTime, &customers[i].processTime);
if(customers[i].processTime > 60) { //如果单次处理时间超过60,当作60处理
customers[i].processTime = 60;
}
strcpy(customers[i].name, name);
customerId[name] = i;
}
int totalTime = 0; //总等待时间
int window = customers[0].arriveTime; //一开始的窗口时间应该设置为最先到达的顾客的到达时间
for(int i = 0; i < N; i++) {
if(visited[i]) { //如果该顾客已经被处理过了,则跳过本次循环
continue;
}
if(friendMap.find(customers[i].name) == friendMap.end()) { //如果该顾客不属于任何一个朋友圈
if(window > customers[i].arriveTime) { //如果窗口时间大于顾客的到达时间
totalTime += window - customers[i].arriveTime; //总等待时间增加
window += customers[i].processTime; //窗口时间加上该顾客的处理时间
}else{
window = customers[i].arriveTime + customers[i].processTime; //窗口时间更新为顾客的到达时间加上该顾客的处理时间
}
visited[i] = true;
result.push_back(customers[i].name);
continue; //跳过本次循环
}
int friendID = friendMap[customers[i].name];
sort(friends[friendID].begin(), friends[friendID].end(), cmp); //对该顾客所属朋友圈的朋友按到达顺序进行排序
for(int j = 0; j < friends[friendID].size(); j++) {
int id = customerId[friends[friendID][j]];
if(j > 0 && customers[id].arriveTime > window){ //如果下一个朋友的在window的空闲时间之前没有到达,则无法插队
break;
}
if(visited[id]){
continue;
}
if(window > customers[id].arriveTime) {
totalTime += window - customers[id].arriveTime;
window += customers[id].processTime;
} else {
window = customers[id].arriveTime + customers[id].processTime;
}
visited[id] = true;
result.push_back(friends[friendID][j]);
}
}
for(int i = 0; i < result.size(); i++) { //输出结果
printf("%s\n", result[i].c_str());
}
printf("%.1f\n", totalTime * 1.0 / N);
return 0;
}
bool cmp(string s1, string s2) {
return customerId[s1] < customerId[s2];
}
C++解题报告: