《计算机考研复试上机指导全书习题集》试读版
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
num[len] = sum % 10; sum /= 10; ++len; } //使用 do...while 的写法
=5=
int len = 0; do {
num[len] = sum % 10; sum /= 10; ++len; }while(sum);
Note 2: 注意最低位后面是不需要输出逗号的,所以需要在输出逗号时判断是否是最低位。
样例解释
Sample One 有两个窗口,每个窗口前最多排两个人,初始状态下 7 个客户都在黄线外,然后按照选择窗口
的规则进行排队,得到如图的排队情况,其中每个客户右下角的中括号中的数字表示该客户当前剩 余的服务时间。
由于 1 号客户的剩余服务时间比 2 号客户更短,因此 1 号客户在 08:01 时先行服务完毕,5 号 客户排到 1 号窗口后面,同时 2 号客户的剩余服务时间减少 1 分钟,得到下图 08:01 的状态图。接 下来的步骤过程与此类似,பைடு நூலகம்里不再赘述,读者可以从图中得到整个过程,其中在 17:00 时 7 号客 户将无法被服务,因此 7 号客户应当输出 Sorry。
= 37 =
考察点
排队问题
思路
Step 1 考虑一个事实:当一位客户进入某一窗口的队列时,他的服务结束时间就已经确定了,即当前
在该窗口排队的所有人的服务时间之和。而在所有窗口排满后,剩余客户能够去排队的时间点是所 有窗口最早结束的队首客户,也就是说,在所有窗口排满的情况下,每当有一个窗口的队首客户服 务结束(结束时间相同的,窗口 ID 小的视为先结束),剩余客户的第一个就会排到那个窗口最后面 去。于是我们可以为窗口建立一个结构体 Window,存放该窗口当前队伍的最后服务时间 endTime 和队首客户的服务结束时间 popTime,并维护一个该窗口的排队队列 q,如下所示:
//服务结束时间、服务需要时间
int main() {
int inIndex = 0;
//当前第一个未入队的客户编号
scanf("%d%d%d%d", &n, &m, &k, &query); //窗口数、窗口人数上限、客户数、查询数
for(int i = 0; i < k; i++) {
scanf("%d", &needTime[i]); //读入服务需要时间
//寻找所有窗口的最小 popTime
for(int i = 0; i < n; i++) {
if(window[i].popTime < minPopTime) {
idx = i;
minPopTime = window[i].popTime;
}
}
= 39 =
//找到最小 popTime 的窗口编号为 idx,下面更新该窗口的队列情况
如果 Step 2 中已经把所有窗口排满(显然如果没有排满,就不存在剩余在黄线外的客户),那 么在该步中将剩下的客户想办法入队。由 Step 1 可以知道,在所有窗口排满的情况下,每当有一个 窗口的队首客户服务结束(结束时间相同的,窗口 ID 小的视为先结束),剩余客户的第一个就会排 到那个窗口最后面去。这样对每一个剩余的客户,我们可以选出当前所有窗口中 popTime 最小的窗 口(popTime 相同的选择窗口 ID 较小的),将客户排到该窗口的队列后面,并更新该窗口的 endTime 和 popTime,其中 endTime 将作为刚入队的客户的服务结束时间(即作为答案)保存下来。 Step 4
对每一个输入的查询客户编号,如果他的服务开始时间在 17:00 之后(含 17:00),则输出 Sorry; 否则输出他的服务结束时间。
注意点
Note 1: 在 17:00 之后(含 17:00)开始服务的客户应当输出 Sorry,否则都应当输出服务结束时间(即 便服务结束时间超过了 17:00)。
W.popTime += needTime[W.q.front()];
//更新该窗口的 popTime
ans[inIndex] = W.endTime; //客户 inIndex 的服务结束时间为该窗口的 endTime
}
for(int i = 0; i < query; i++) {
scanf("%d", &q);
}
for(int i = 0; i < n; i++) { //初始化每个窗口的 popTime 和 endTime 为 08:00
window[i].popTime = window[i].endTime = convertToMinute(8, 0);
}
for(int i = 0; i < min(n * m, k); i++) { //注意是 min(n*m, k)
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int maxNode = 1111;
int n, m, k, query, q;
int convertToMinute(int h, int m) {
参考代码
#include <cstdio> int num[10]; int main() {
int a, b, sum; scanf("%d%d",&a, &b); sum = a + b; //将 a+b 赋值给 sum if(sum < 0) { //sum 为负数时,输出负号并取 sum 的相反数
Note 2: 当一个客户服务结束时,下一个客户的服务将立即开始,剩余客户也立即入队,中间无缝 对接,不产生额外时间。
Note 3: 关于时间的处理有一个小小的技巧,就是把时间都转换为分钟,即把 hh:mm 形式的时间全 部转换为分钟数 hh*60+mm,以便于时间的处理和比较。
= 38 =
参考代码
return h * 60 + m; //转换时间为分钟,方便时间处理
}
struct Window {
int endTime, popTime; //窗口当前队伍的最后服务时间、队首客户的服务结束时间
queue<int> q; //队列
} window[20];
int ans[maxNode], needTime[maxNode];
Window& W = window[idx]; //引用,下文中用 W 代替 window[idx],行文更清晰
W.q.pop();
//队首客户离开
W.q.push(inIndex); //客户 inIndex 入队
W.endTime += needTime[inIndex];
//更新该窗口队列的 endTime
printf("-"); sum = -sum; } int len = 0; //len 存放 sum 的长度 if(sum == 0) num[len++] = 0; //sum 为 0 时特殊处理 while(sum) { //将 sum 存入数组 num[]中,其中 sum 的低位存放到 num[]的低位 num[len++] = sum % 10; //将 sum 的末位 sum%10 存放到 num[len],然后 len++ sum /= 10; //去除 sum 的末位 } for(int k = len - 1; k >= 0; k--) { //从高位开始输出 printf("%d", num[k]); if(k > 0 && k % 3 == 0) printf(","); //每三位一个逗号,最后一位除外 } return 0; }
struct Window { int endTime, popTime; queue<int> q;
} window[20]; Step 2
在 08:00 时刻,只要窗口的队列没满,就把客户按照窗口编号为 0, 1, 2, ..., n - 1, 0, 1, 2, ..., n - 1, 0, 1, 2, ...的循环顺序进行入队,且在安排的过程中不断更新窗口的 endTime 和 popTime,其中 endTime 将直接作为刚入队客户的服务结束时间(即作为答案)保存下来,而 popTime 仅在安排每个窗口的 第一客户时更新。 Step 3
《计算机考研复试上机指导全书习题集》试读版
1001. A+B Format (20)
Time Limit: 400 MS Memory Limit: 65536 KB
题意
给出两个整数 a、b(不超过 10^9),求 a+b 的值,并按照 xxx,xxx,xxx,xxx 的格式输出。
样例解释
Sample One -1000000 + 9 = -999991 按照格式输出为-999,991。
=6=
1014. Waiting in Line (30)
Time Limit: 400 MS Memory Limit: 65536 KB
题意
某银行有 N 个窗口,每个窗口前最多可以排 M 个人。现在有 K 位客户需要服务,每位客户的 服务时长已知。假设所有客户均在 08:00 时刻按客户编号次序等在黄线外,且如果有窗口的排队人 数没有排满(没有达到 M 人),当前在黄线外的第一个客户就会选择这样的窗口中排队人数最少的 窗口去排队(排队人数相同时,选择窗口序号最小的窗口去排队)。给出 Q 个查询,每个查询给出 一位客户的编号,输出这位客户的服务结束时间。注意,如果一个客户在 17:00 之后(含 17:00)还 没有被服务,则不再服务,输出 Sorry;而如果一个客户在 17:00 之前被服务,那么无论他的服务时 长有多长,都会服务完整。
//循环入队
window[inIndex % n].q.push(inIndex);
//更新窗口的服务结束时间 endTime
window[inIndex % n].endTime += needTime[inIndex];
//对窗口的第一个客户,更新 popTime
if(inIndex < n) window[inIndex].popTime = needTime[inIndex];
Note 3: 这题还可以采用下面的写法,不妨拓宽下思路(省略 Step1 的步骤): 在 printf 的格式化输出中,%3d 表示输出三位整数,不满三位的高位补空格;而%03 表示输出三位 整数,不满三位的高位补 0。于是可以得到下面这个简洁的写法,不妨好好理解一下:
if(sum >= 1000000) printf("%d,%03d,%03d", sum/1000000, sum%1000000/1000, sum%1000); else if(sum >= 1000) printf("%d,%03d", sum/1000, sum%1000); else printf("%d", sum);
//当前入队的客户的服务结束时间直接保存作为答案
ans[inIndex] = window[inIndex % n].endTime;
inIndex++;
}
for(; inIndex < k; inIndex++) {
//处理剩余客户的入队
int idx = -1, minPopTime = 1 << 30;
考察点
字符串处理
思路
Step 1 对输入的两个数字 a 与 b 进行累加,并赋值给 sum。之后判断累加后得到的 sum 是否为负数,
如果是负数,则负号先行输出,并令 sum = -sum 来取正。 Step2
把 sum 的每一位存到数组中(例如 123 存到数组 num[]中就是 num[0] = 3、num[1] = 2、num[2] = 1,即 sum 的低位存储到 num[]的低位),之后从高位开始输出数组元素,每输出 3 个数字输出 1 个逗号,最后 3 个数字后面不输出。
注意点
Note 1: 把 sum 存放到数组时,如果是用 while 写的话,就要注意 0 这个数据需要特殊处理,否则 while 循环进不去,导致 len 会等于 0;而如果用 do while 循环写的话,则可以不用考虑。
//使用 while 的写法 int len = 0; if(sum == 0) num[len++] = 0; while(sum) {
=5=
int len = 0; do {
num[len] = sum % 10; sum /= 10; ++len; }while(sum);
Note 2: 注意最低位后面是不需要输出逗号的,所以需要在输出逗号时判断是否是最低位。
样例解释
Sample One 有两个窗口,每个窗口前最多排两个人,初始状态下 7 个客户都在黄线外,然后按照选择窗口
的规则进行排队,得到如图的排队情况,其中每个客户右下角的中括号中的数字表示该客户当前剩 余的服务时间。
由于 1 号客户的剩余服务时间比 2 号客户更短,因此 1 号客户在 08:01 时先行服务完毕,5 号 客户排到 1 号窗口后面,同时 2 号客户的剩余服务时间减少 1 分钟,得到下图 08:01 的状态图。接 下来的步骤过程与此类似,பைடு நூலகம்里不再赘述,读者可以从图中得到整个过程,其中在 17:00 时 7 号客 户将无法被服务,因此 7 号客户应当输出 Sorry。
= 37 =
考察点
排队问题
思路
Step 1 考虑一个事实:当一位客户进入某一窗口的队列时,他的服务结束时间就已经确定了,即当前
在该窗口排队的所有人的服务时间之和。而在所有窗口排满后,剩余客户能够去排队的时间点是所 有窗口最早结束的队首客户,也就是说,在所有窗口排满的情况下,每当有一个窗口的队首客户服 务结束(结束时间相同的,窗口 ID 小的视为先结束),剩余客户的第一个就会排到那个窗口最后面 去。于是我们可以为窗口建立一个结构体 Window,存放该窗口当前队伍的最后服务时间 endTime 和队首客户的服务结束时间 popTime,并维护一个该窗口的排队队列 q,如下所示:
//服务结束时间、服务需要时间
int main() {
int inIndex = 0;
//当前第一个未入队的客户编号
scanf("%d%d%d%d", &n, &m, &k, &query); //窗口数、窗口人数上限、客户数、查询数
for(int i = 0; i < k; i++) {
scanf("%d", &needTime[i]); //读入服务需要时间
//寻找所有窗口的最小 popTime
for(int i = 0; i < n; i++) {
if(window[i].popTime < minPopTime) {
idx = i;
minPopTime = window[i].popTime;
}
}
= 39 =
//找到最小 popTime 的窗口编号为 idx,下面更新该窗口的队列情况
如果 Step 2 中已经把所有窗口排满(显然如果没有排满,就不存在剩余在黄线外的客户),那 么在该步中将剩下的客户想办法入队。由 Step 1 可以知道,在所有窗口排满的情况下,每当有一个 窗口的队首客户服务结束(结束时间相同的,窗口 ID 小的视为先结束),剩余客户的第一个就会排 到那个窗口最后面去。这样对每一个剩余的客户,我们可以选出当前所有窗口中 popTime 最小的窗 口(popTime 相同的选择窗口 ID 较小的),将客户排到该窗口的队列后面,并更新该窗口的 endTime 和 popTime,其中 endTime 将作为刚入队的客户的服务结束时间(即作为答案)保存下来。 Step 4
对每一个输入的查询客户编号,如果他的服务开始时间在 17:00 之后(含 17:00),则输出 Sorry; 否则输出他的服务结束时间。
注意点
Note 1: 在 17:00 之后(含 17:00)开始服务的客户应当输出 Sorry,否则都应当输出服务结束时间(即 便服务结束时间超过了 17:00)。
W.popTime += needTime[W.q.front()];
//更新该窗口的 popTime
ans[inIndex] = W.endTime; //客户 inIndex 的服务结束时间为该窗口的 endTime
}
for(int i = 0; i < query; i++) {
scanf("%d", &q);
}
for(int i = 0; i < n; i++) { //初始化每个窗口的 popTime 和 endTime 为 08:00
window[i].popTime = window[i].endTime = convertToMinute(8, 0);
}
for(int i = 0; i < min(n * m, k); i++) { //注意是 min(n*m, k)
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int maxNode = 1111;
int n, m, k, query, q;
int convertToMinute(int h, int m) {
参考代码
#include <cstdio> int num[10]; int main() {
int a, b, sum; scanf("%d%d",&a, &b); sum = a + b; //将 a+b 赋值给 sum if(sum < 0) { //sum 为负数时,输出负号并取 sum 的相反数
Note 2: 当一个客户服务结束时,下一个客户的服务将立即开始,剩余客户也立即入队,中间无缝 对接,不产生额外时间。
Note 3: 关于时间的处理有一个小小的技巧,就是把时间都转换为分钟,即把 hh:mm 形式的时间全 部转换为分钟数 hh*60+mm,以便于时间的处理和比较。
= 38 =
参考代码
return h * 60 + m; //转换时间为分钟,方便时间处理
}
struct Window {
int endTime, popTime; //窗口当前队伍的最后服务时间、队首客户的服务结束时间
queue<int> q; //队列
} window[20];
int ans[maxNode], needTime[maxNode];
Window& W = window[idx]; //引用,下文中用 W 代替 window[idx],行文更清晰
W.q.pop();
//队首客户离开
W.q.push(inIndex); //客户 inIndex 入队
W.endTime += needTime[inIndex];
//更新该窗口队列的 endTime
printf("-"); sum = -sum; } int len = 0; //len 存放 sum 的长度 if(sum == 0) num[len++] = 0; //sum 为 0 时特殊处理 while(sum) { //将 sum 存入数组 num[]中,其中 sum 的低位存放到 num[]的低位 num[len++] = sum % 10; //将 sum 的末位 sum%10 存放到 num[len],然后 len++ sum /= 10; //去除 sum 的末位 } for(int k = len - 1; k >= 0; k--) { //从高位开始输出 printf("%d", num[k]); if(k > 0 && k % 3 == 0) printf(","); //每三位一个逗号,最后一位除外 } return 0; }
struct Window { int endTime, popTime; queue<int> q;
} window[20]; Step 2
在 08:00 时刻,只要窗口的队列没满,就把客户按照窗口编号为 0, 1, 2, ..., n - 1, 0, 1, 2, ..., n - 1, 0, 1, 2, ...的循环顺序进行入队,且在安排的过程中不断更新窗口的 endTime 和 popTime,其中 endTime 将直接作为刚入队客户的服务结束时间(即作为答案)保存下来,而 popTime 仅在安排每个窗口的 第一客户时更新。 Step 3
《计算机考研复试上机指导全书习题集》试读版
1001. A+B Format (20)
Time Limit: 400 MS Memory Limit: 65536 KB
题意
给出两个整数 a、b(不超过 10^9),求 a+b 的值,并按照 xxx,xxx,xxx,xxx 的格式输出。
样例解释
Sample One -1000000 + 9 = -999991 按照格式输出为-999,991。
=6=
1014. Waiting in Line (30)
Time Limit: 400 MS Memory Limit: 65536 KB
题意
某银行有 N 个窗口,每个窗口前最多可以排 M 个人。现在有 K 位客户需要服务,每位客户的 服务时长已知。假设所有客户均在 08:00 时刻按客户编号次序等在黄线外,且如果有窗口的排队人 数没有排满(没有达到 M 人),当前在黄线外的第一个客户就会选择这样的窗口中排队人数最少的 窗口去排队(排队人数相同时,选择窗口序号最小的窗口去排队)。给出 Q 个查询,每个查询给出 一位客户的编号,输出这位客户的服务结束时间。注意,如果一个客户在 17:00 之后(含 17:00)还 没有被服务,则不再服务,输出 Sorry;而如果一个客户在 17:00 之前被服务,那么无论他的服务时 长有多长,都会服务完整。
//循环入队
window[inIndex % n].q.push(inIndex);
//更新窗口的服务结束时间 endTime
window[inIndex % n].endTime += needTime[inIndex];
//对窗口的第一个客户,更新 popTime
if(inIndex < n) window[inIndex].popTime = needTime[inIndex];
Note 3: 这题还可以采用下面的写法,不妨拓宽下思路(省略 Step1 的步骤): 在 printf 的格式化输出中,%3d 表示输出三位整数,不满三位的高位补空格;而%03 表示输出三位 整数,不满三位的高位补 0。于是可以得到下面这个简洁的写法,不妨好好理解一下:
if(sum >= 1000000) printf("%d,%03d,%03d", sum/1000000, sum%1000000/1000, sum%1000); else if(sum >= 1000) printf("%d,%03d", sum/1000, sum%1000); else printf("%d", sum);
//当前入队的客户的服务结束时间直接保存作为答案
ans[inIndex] = window[inIndex % n].endTime;
inIndex++;
}
for(; inIndex < k; inIndex++) {
//处理剩余客户的入队
int idx = -1, minPopTime = 1 << 30;
考察点
字符串处理
思路
Step 1 对输入的两个数字 a 与 b 进行累加,并赋值给 sum。之后判断累加后得到的 sum 是否为负数,
如果是负数,则负号先行输出,并令 sum = -sum 来取正。 Step2
把 sum 的每一位存到数组中(例如 123 存到数组 num[]中就是 num[0] = 3、num[1] = 2、num[2] = 1,即 sum 的低位存储到 num[]的低位),之后从高位开始输出数组元素,每输出 3 个数字输出 1 个逗号,最后 3 个数字后面不输出。
注意点
Note 1: 把 sum 存放到数组时,如果是用 while 写的话,就要注意 0 这个数据需要特殊处理,否则 while 循环进不去,导致 len 会等于 0;而如果用 do while 循环写的话,则可以不用考虑。
//使用 while 的写法 int len = 0; if(sum == 0) num[len++] = 0; while(sum) {