复杂输入输出

复杂输入输出

  • 规律

    • 复杂输入与输出,用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;
      } 
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦想总比行动多

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值