复杂输入输出
-
规律
- 复杂输入与输出,用cin和cout可能会超时,最好使用scanf。
-
A 1095:排序 + 输入所有数据+从所有数据中挑选有效数据;一辆车的in与out匹配,计算停车时间。(记录匹配问题)
-
思路:
①定义结构体变量all来存储所有记录,valid来存储有效记录,这是打破从输入开始处理的常规思路。
②对所有all数组记录,先按车牌号从小到大排序,然后再按时间从小到大排序。排序之后就可以方便地进行匹配。即寻找同一辆车(车牌号相同)中相邻时间并且一个为in另一个为out的记录。将有效记录存储到valid结构体中
③ 按时间顺序遍历valid结构体,然后进入查询阶段,由于查询的时刻是按时间顺序递增的,所以可以设置一个变量now,用来指向valid数组里面的记录,使得now指向的记录时刻不超过本次想要查询的时刻;同时设置一个变量numCar来记录当前校园内的车辆数。
④遍历记录停车时间的parkTime数组,输出总停留时间等于最大停留时间的车牌号和对应时间。 -
注意点
①strcmp函数使用。返回值 < 0,表示str1 小于 str2;返回值 = 0, 表示相等;返回值 > 0,表示str1大于str2.
//strcmp函数在cmp中比较字符数组 struct node{ char s[30]; int time; } bool cmp(node a, node b){ if(strcmp(a.s, b.s) != 0){//表示两个字符数组不相等 return strcmp(a.s, b.s) < 0; //表示升序排序 } else return a.time < b.time; } //strcmp函数比较一个字符串和一个字符数组变量 char s[10]; if(strcmp(s, "in") == 0){ …… }
②map<string, int> 中可以存放字符数组类型。放入后会从字符数组类型变为string类型。
char s[100]; cin >> s; mp[s] = 2;//char数组类型可以直接存入到map的string类型中,存入后char数组将变成string类型 auto it = mp.begin(); printf("%s %d", (it->first).c_str(), it->second);
-
代码实现
#include<bits/stdc++.h> using namespace std; const int maxn = 10010; struct Car{ char id[8];//车牌号 int time; //记录的时刻 char status[4];//in或者out }all[maxn], valid[maxn];//all为所有记录,valid为有效记录。这是本题解答打破常规之处,将所有数据存储后再进行处理 int num; //记录有效条数 map<string, int> parkTime; //车牌号--》总停留时间 //将时间转换为以s为单位 int timeToInt(int hh, int mm, int ss){ return hh * 3600 + mm * 60 + ss; } //先按车牌号从小到大排序,然后再按时间从小到大排序。这是本题点睛之处 bool cmpByIdAndTime(Car a, Car b){ if(strcmp(a.id, b.id))return strcmp(a.id, b.id) < 0; else return a.time < b.time; } //只按时间从小到大排序 bool cmpByTime(Car a, Car b){ return a.time < b.time; } int main(){ int n, k, hh, mm, ss; scanf("%d%d", &n, &k); for(int i = 0; i < n; i++){ scanf("%s %d:%d:%d %s", all[i].id, &hh, &mm, &ss, all[i].status); all[i].time = timeToInt(hh, mm, ss); } //按车牌号和时间排序 sort(all, all + n, cmpByIdAndTime); int maxTime = -1; //最长总停留时间 for(int i = 0; i < n - 1; i++){ //如果是同一辆车,并且一个记录是in,另一个是out if(!strcmp(all[i].id, all[i+1].id) && !strcmp(all[i].status, "in") && !strcmp(all[i+1].status, "out")){ valid[num++] = all[i]; //记录有效记录 valid[num++] = all[i+1]; int inTime = all[i+1].time - all[i].time; //此次停留时间 if(parkTime.count(all[i].id) == 0){ parkTime[all[i].id] = 0; } parkTime[all[i].id] += inTime; //增加这个车牌号的停留时间 maxTime = max(maxTime, parkTime[all[i].id]);//更新最大总停留时间 } } sort(valid, valid + num, cmpByTime);//将有效数据按时间顺序进行排序 //now指向不超过当前查询时间的记录,numCar为当前校园内车辆数 int now = 0, numCar = 0; for(int i = 0; i < k; i++){ scanf("%d:%d:%d", &hh, &mm, &ss); int time = timeToInt(hh, mm, ss); //让now处理至当前时间 while(now < num && valid[now].time <= time){ if(!strcmp(valid[now].status, "in"))numCar++;//车辆进入 else numCar--;//车辆离开 now++; //指向下一条记录 } printf("%d\n", numCar);//输出该时刻校园内车辆数 } //遍历所有车牌号,输出所有最长总停留时间的车牌号 map<string, int>::iterator it; for(it = parkTime.begin(); it != parkTime.end(); it++){ if(it->second == maxTime){ printf("%s ", it->first.c_str()); } } //输出最长总停留时间 printf("%02d:%02d:%02d\n", maxTime/3600, maxTime%3600/60, maxTime%60); return 0; }
-
-
A 1016 记录匹配问题:计算电话账单
-
思路:
-
代码实现:
#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; int toll[25];//资费数组 struct Record{ char name[25]; int month,dd,hh,mm; bool status;//状态标记 }rec[1010],temp; //比较函数,不仅可以是对分数等进行排序,也可以让记录按想要的结果进行排序【一个重点】 bool cmp(Record a,Record b){ if(strcmp(a.name,b.name)!=0)return strcmp(a.name,b.name)<0;//名字不同,按字典序排列 else if(a.month!=b.month)return a.month<b.month;//名字相同,按月份排序 else if(a.dd!=b.dd)return a.dd<b.dd; else if(a.hh!=b.hh)return a.hh<b.hh; else return a.mm<b.mm;//最后按分钟大小进行排序 } void get_ans(int on,int off,int &time,int &money)//此处用&,表示time和money仍然要返回到主函数中进行处理 { temp=rec[on];//temp只是简化代码书写 while(temp.dd<rec[off].dd||temp.hh<rec[off].hh||temp.mm<rec[off].mm){ time++;//总分钟数,通过不断加1实现计算 money+=toll[temp.hh];//每分钟话费增加toll[temp.hh] temp.mm++;//当前时间加1分钟 if(temp.mm>=60){//当分钟数达到60,计算小时数 temp.mm=0; temp.hh++; } if(temp.hh>=24){//当小时数达到60,计算天数 temp.hh=0; temp.dd++; } } } int main(){ for(int i=0;i<24;i++){ scanf("%d",&toll[i]);//输入资费 } int n; scanf("%d",&n); char line[10];//暂时存储状态 for(int i=0;i<n;i++){ scanf("%s",rec[i].name); scanf("%d:%d:%d:%d",&rec[i].month,&rec[i].dd,&rec[i].hh,&rec[i].mm); scanf("%s",line); if(strcmp(line,"on-line")==0){ //状态因为只有两种,把他变为数字,更加方便处理 rec[i].status=1; } else rec[i].status=0; } sort(rec,rec+n,cmp); int on=0,off,next;//next用来判断是否到达下一个人,简化问题 int allmoney; while(on<n){ int needPrint=0; next=on;//从当前位置开始寻找下一个用户 while(next<n&&strcmp(rec[next].name,rec[on].name)==0)//仍然为同一个人,否则将不是同一个人 { if(needPrint==0&&rec[next].status==1)needPrint=1;//找到一个on else if(needPrint==1&&rec[next].status==0)needPrint=2;//找到一个off next++; //记录同一个人的记录在结构体中的下标 } if(needPrint<2){//如果没有找到,说明此人不需要输出,即不用进行后面的操作,而对下一个人进行查找 on=next; continue; } allmoney=0; printf("%s %02d\n",rec[on].name,rec[on].month); while(on<next){ while(on<next-1&&!(rec[on].status==1&&rec[on+1].status==0))on++;//寻找连续的on与off off=on+1; if(off==next) {//此人的on与off配对已经输出完毕 on=next; break; } printf("%02d:%02d:%02d ",rec[on].dd,rec[on].hh,rec[on].mm); printf("%02d:%02d:%02d ",rec[off].dd,rec[off].hh,rec[off].mm); int time=0,money=0; get_ans(on,off,time,money); allmoney += money; printf("%d $%.2f\n",time,money/100.0); on =off+1;//完成一个配对,寻找下一个配对 } printf("Total amount: $%.2f\n",allmoney/100.0); } return 0; }
-
-
A 1014 银行排队办理业务类型题(本题给出黄线内和黄线外的不同操作,求每个客户结束服务的时间)
-
思路:
①结构体变量记录每个窗口的结束时间以及一个popTime表示第一个人结束时间;另外再定义一个队列queue q。
②初始化每个窗口的popTIme和endTime为8:00, 这里时间可以用min来表示
③ 黄线内处理。首先在总人数和总共容量之间取最小值,然后循环这个最小值。在for循环内部,将顾客的编号压入到相应窗口的队列中,接着,更新每个窗口的endTIme和popTime。同时,对于黄线内的顾客,可以直接计算服务结束时间。
④ 对剩下的用户进行处理。首先,寻找所有窗口中的最小popTIme,将这个窗口的队首元素弹出,压入此时黄线外的用户。然后更新这个窗口popTIme和endTime。同时,计算剩下用户的服务结束时间。
⑤查询,对服务开始时间大于等于17:00的顾客输出Sorry,否则输出服务结束时间。 -
代码实现
#include<bits/stdc++.h> using namespace std; int n, m, k, q; const int maxn = 1010; int needTime[maxn], ans[maxn];//所需要服务时间和服务结束时间 struct node{ int popTime, endTime; queue<int> q; }window[20]; int cal(int h, int m){ return h * 60 + m; } int main(){ int inIndex = 0, id; cin >> n >> m >> k >> q; for(int i = 0; i < k; i++){ cin >> needTime[i]; } //②初始化 每个窗口的popTIme和endTime为8:00 for(int i = 0; i < n; i++){ window[i].popTime = window[i].endTime = cal(8, 0); } //②处理黄线内的人 for(int i = 0; i < min(k, m*n); i++){ //首先入队 window[i % n].q.push(inIndex); //然后更新每个窗口的popTime和endTime window[i%n].endTime += needTime[inIndex]; if(i < n)window[i%n].popTime = needTime[inIndex]; //接着计算黄线内人的服务结束时间 ans[i] = window[i%n].endTime; inIndex++; } //③处理黄线外的人 for(; inIndex < k; inIndex++){ //首先寻找最小popTime的窗口 int idx = -1, minPop = 1000000000; for(int i = 0; i < n; i++){ if(window[i].popTime < minPop){ minPop = window[i].popTime; idx = i; } } //然后将这个窗口的队首出队,并压入黄线外的人的编号 window[idx].q.pop(); window[idx].q.push(inIndex); //更新这个窗口的endTime和popTIme window[idx].endTime += needTime[inIndex]; window[idx].popTime += needTime[window[idx].q.front()]; //计算这个顾客的服务结束时间 ans[inIndex] = window[idx].endTime; } //④查询输入 for(int i = 0; i < q; i++){ cin >> id; //判断服务开始时间是否晚于17:00 if(ans[id-1] - needTime[id-1] >= cal(17, 0)){ printf("Sorry\n"); } else{ printf("%02d:%02d\n", ans[id-1] / 60, ans[id-1] % 60); } } return 0; }
-
-
A1017 银行排队办理业务类型题(本题给出客户到达时间以及服务时间,求所有客户平均等待时间)
-
思路
①定义一个结构体变量存储到来时间和服务时间;
②以数字endTime存放每个窗口当前客户的服务结束时间。初始化服务结束时间为8:00。接着按到达时间对所有客户升序排序
③对所有用户进行处理。首先找到最早结束服务的窗口,然后分情况讨论:1)如果队首客户的到达时间比该最早空闲的窗口的时间要晚, 那么客户可以直接前往服务,等待时间为0,即只需令当前窗口的endTIme值增加客户的服务时间。 2) 如果队首客户的到达时间比该最早空闲的窗口的时间要早,则有等待时间,然后更新endTIme值。
-
代码实现
#include<bits/stdc++.h> using namespace std; const int k = 111; const int INF = 1000000000; struct customer{ int comeTime, serveTime; }newCustomer; vector<customer> custom; int convertTime(int h, int m, int s){ return h * 3600 + m * 60 + s; } bool cmp(customer a, customer b){ return a.comeTime < b.comeTime; } int endTime[k];//记录每个窗口结束服务的时间 int main(){ int c, w, totTime = 0; //totTime记录总等待时长 int stTime = convertTime(8,0,0); int edTime = convertTime(17, 0, 0);//银行工作时间 cin >> c >> w; //客户数、窗口数 for(int i = 0; i < w; i++)endTime[i] = stTime;//初始化 for(int i = 0; i < c; i++){ int h, m, s, serveTime; scanf("%d:%d:%d %d", &h, &m, &s, &serveTime); int comeTime = convertTime(h, m, s); if(comeTime > edTime)continue; //超过关门时间,不计算 newCustomer.comeTime = comeTime; newCustomer.serveTime = serveTime * 60; custom.push_back(newCustomer); //新客户加入结构体中 } sort(custom.begin(), custom.end(), cmp); //按到达时间升序排序 for(int i = 0; i < custom.size(); i++){//对于每一个客户 //寻找最早结束服务的窗口 int idx = -1, minEndTime = INF;//选择当前最早服务结束的窗口 for(int j = 0; j < w; j++){ if(endTime[j] < minEndTime){ minEndTime = endTime[j]; idx = j; } } //分情况讨论 //如果队首客户到来时间是在窗口空闲之后 if(endTime[idx] <= custom[i].comeTime){ endTime[idx] = custom[i].comeTime + custom[i].serveTime; } else{ //客户到来时间,没有窗口空闲 totTime += (endTime[idx] - custom[i].comeTime);//等待时间计入 endTime[idx] += custom[i].serveTime; //该窗口结束时间更新 } } if(custom.size() == 0)cout << "0.0"; else printf("%.1f", totTime / 60.0 / custom.size()); return 0; }
-