b_pat_银行排队(全部转化为秒+排序+堆)
Queueing at Bank
假设一家银行有 K 个服务窗口。窗户前面有一条黄线,将等候区分为两部分。
所有客户都必须在黄线后面排队等候,直到轮到他/她服务并且有可用的窗口为止。
假定一个窗口不能被单个客户占用超过 1 小时,即如果某位顾客的业务已经办理了一小时,则立即终止此项业务。
现在给定每个客户的到达时间 T 和业务办理时间 P,请计算所有客户的平均等待时间。
输入格式
第一行包含两个整数 N 和 K,分别表示客户数量以及窗口数量。
接下来 N 行,每行包含两个时间,分别是一个客户的到达时间,用 HH:MM:SS 表示,以及一个客户的业务办理时间 P(单位:分钟)。
HH 在 [00,23] 范围内,MM 和 SS 都在 [00,59] 范围内。
请注意,银行的营业时间为 08:00 至 17:00。
任何人提前到达都必须排队等候至 08:00,而任何人来得太晚(在 17:00:01 或之后到达)都将不被服务也无需计入平均值。
注意只要客户在17:00之前排上队,则即使办理业务时超过17:00,也会被服务。
输出格式
输出平均等待时间(单位:分钟),结果保留一位小数。
注意,从到达银行至开始办理业务这一期间视为等待期间。
数据范围
1≤N≤104,
1≤K≤100
思路
这里的输入时间有时分秒不太好比较,可以全部转化为秒(防止产生小数)
一开始有k个空窗口,每次有客户来的时候,优先安排到先结束办理的窗口内为候选客人服务
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5, s=8*3600, e=17*3600;
struct node{
int arrive_time, service_time;
}A[N];
bool cmp(node &a, node &b){
return a.arrive_time<b.arrive_time;
}
int main() {
int n,k,hour,minute,second,service_time;;
scanf("%d%d", &n,&k);
for (int i=0; i<n; i++) {
scanf("%d:%d:%d%d", &hour, &minute, &second, &service_time);
A[i].arrive_time=hour*3600+minute*60+second, A[i].service_time=min(service_time, 60)*60;
}
sort(A, A+n, cmp);
priority_queue<int, vector<int>, greater<int>> q;
for (int i=0; i<k; i++) q.push(s); //k个窗口
int tot=0,cnt=0;
for (int i=0; i<n; i++) {
int at=A[i].arrive_time, st=A[i].service_time;
if (at>e) break;
int start_time=max(q.top(), at); q.pop();
tot+=start_time-at; cnt++;
q.push(start_time+st);
}
printf("%.1f\n", (double) tot/cnt/60.0);
return 0;
}
Waiting in Line
在黄线以内的区域,每个窗口前都可以排一队人,每队最多可以排 M 个人,当 N 个窗口前的队伍都排满时,第 NM+1 个顾客以及以后的顾客只能在黄线以外的区域等候。黄线外的所有客户统一排成一个长队。
每当客户进入黄线以内时,他会选择到当前排队人数最少的窗口处排队等待办理业务。当多个窗口前排队人数最少时,客户会选择窗口编号更小的窗口处排队等待办理业务。
思路
按照条件找窗口,用use记录每个窗口的总等待时间,id为x的用户如果去了c窗口,则它的完成时间为use[c]+t(t为自己的处理时间)
这题服了,m好像没有真正被用到,只是再算全局限制人数的时候用了一下;其他
#include<bits/stdc++.h>
using namespace std;
const int N=25;
queue<int> win[N];
unordered_map<int, int> mp;
int main() {
int n,m,k,q; cin>>n>>m>>k>>q; //n个窗口,每个窗口的最大容量m个,1~k个客户的处理时间,q个查询
int limit=n*m, use[k+1]; memset(use, 0, sizeof use);
for (int i=1; i<=k; i++) {
int t; cin>>t;
int c=0;
for (int j=0; j<n; j++) {
if (i<=limit && win[j].size()<win[c].size()) c=j;
else if (i>limit && win[j].front()<win[c].front()) c=j;
}
if (i>limit) win[c].pop();
use[c]+=t;
if (use[c]-t<540) mp[i]=use[c]; //540是指8~17点的总分钟数
win[c].push(use[c]);
}
for (int i=0; i<q; i++) {
int x; cin>>x;
if (mp.count(x)) {
int t=mp[x];
printf("%02d:%02d\n", t/60+8, t%60);
} else {
cout <<"Sorry\n";
}
}
return 0;
}
Mice and Rice
一开始有n个耗子组成了n/m队(m为每队的数量),每次每队最重的胜出,游戏持续到只剩下一只耗子,问最后的排名;
#include<bits/stdc++.h>
using namespace std;
struct node {
int oIdx, w, rk, init_pos; //原始下标、体重、排名、游戏开始时的位置
};
bool cmp(node& a, node& b) {
return a.init_pos<b.init_pos;
}
bool cmp1(node& a, node& b) {
return a.oIdx<b.oIdx;
}
struct cmp_in_pq{
bool operator()(node& a, node& b){
return a.w<b.w;
}
};
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n,m,id; cin>>n>>m; //n老鼠的数量,m每支队伍的总人树
node A[n];
for (int i=0; i<n; i++) cin>>A[i].w, A[i].oIdx=i;
for (int i=0; i<n; i++) cin>>id, A[id].init_pos=i; //编号为id的老鼠在位置i
sort(A, A+n, cmp); //将老鼠排成题目给定的初始序列,这样入队才符合题目需求
queue<node> q; for (int i=0; i<n; i++) q.push(A[i]);
priority_queue<node, vector<node>, cmp_in_pq> maxQ;
while (q.size()>1) { //一共有g=q.size()/m组
int sz=q.size(), g=sz/m+(sz%m?1:0), rk=g+1;
for (int i=0; i<g; i++) {
for (int j=0; j<m && i*m+j<sz; j++) {
maxQ.push(q.front()); q.pop(); //将每组的老鼠进堆,
}
q.push(maxQ.top()); maxQ.pop(); //将每一组最肥的老鼠重新进堆(晋级)
while (!maxQ.empty()) {
A[maxQ.top().init_pos].rk=rk; maxQ.pop(); //假如有4对,则一定会有4只老鼠晋级,则剩下的老鼠都是第5名
}
}
}
A[q.front().init_pos].rk=1;
sort(A, A+n, cmp1);
for (int i=0; i<n; i++) {
printf("%d", A[i].rk);
if (i!=n-1) printf(" ");
}
return 0;
}