题目描述

学校要举办校庆晚宴,要求学生登记就餐时间,以确定在哪个时间段内就餐的学生数最多,从而调食品的供应量。就餐时间被分为了 N 个时间段,其中 N 可能会非常大,可以假 设 N 为 1 亿,也就是 100000000(这要求程序不能声明长度为 N 的数组或定义 N 个变量), 若未考虑此情况则不能得分。

要求:排序算法的平均时间复杂度不得大于 O(MlogM)。

先输入两个数字 N,M,表示就餐时间被分为了 N 个时间段,一共有 M 个学生。 之后程序输入 M 行,每行两个数字,表示第 i 个学生期望的就餐起始时间段和结束时间段。 程序输出若干行,每行两个数字,表示就餐人数最多时间段的起始时间和终止时间。

测试样例:
输入
5 5
1 2
2 3
1 5
3 5
3 4

输出
3 3

样例解释:
就餐人数最多的时间段的起始时间是第三个时间段,终止时间是第三个时间段。 因为在第三个时间段到第三个时间段,2、3、4、5 号学生都在就餐,这个时间段是就餐 人数最多的时间段。

题目分析

  • 由于就餐时间段可能很多,故这里不可能开一个数组从第一个就餐时间到最后一个可能的就餐时间,故想到可以设立两个数组,一个存储就餐开始的时间,一个存储就餐结束的时间。
  • 再将start和finish合并后排序,经处理得到start和finish中所有出现的时间点。
  • 通过for循环,计算每个时间点应该有的人数。再结合finish数组对其计算哪些时间点之间的人数不变。
  • 得到人数最多的时间端数组。再通过处理后合并相邻时间段,得到了哪些人数时间段最多的结果。

在这里,我把题目分成三个部分

  • 一个是输入就餐的起始时间和就餐的结束时间
  • 一个是归并排序
  • 一个是通过计算得到就餐人数最多的那个时间段,并输出

就餐时间段的登记

没什么好说的,直接上代码

//录入学生登记的时间段,并判断输入是否合法
void registration(int start[], int finish[], int M, int N)
{int i;printf("Please enter the expected time period for each student in turn: \n");for (i = 0; i < M; i++)//for循环进行输入{printf("The expected period of time for %d students: \n", i + 1);scanf("%d", &start[i]);scanf("%d", &finish[i]);if(start[i]<0||finish[i]>N)//排除非法输入{assert(0);}}
}

归并排序

这个我会在我的其他博客中详解,这里直接上代码

void merge(int a[],int b[],int min,int max)//归并排序
{int mid,p;//mid为数组的中间位置,p为从中间位置开始的指针int min2;//记录了数组最小的位置int i,j;min2=min;//min为从最小位置开始的指针if((max-min)<=1)//如果数组为1则return{return;}mid=(max+min)/2;//计算中间位置p=mid;merge(a,b,min,mid);//向中间位置的左边递归merge(a,b,mid,max);//向中间位置的右边递归for(i=min;i<max;)//开始归并排序{if(a[min]>a[p])//左边大于右边{b[i]=a[p];p++;if(p==max)//判断是否排序完成{i++;for(j=min;j<mid;j++,i++){b[i]=a[j];}}else{i++;}}if(a[min]<=a[p])//右边大于左边{b[i]=a[min];min++;if(min==mid)//判断是否排序完成{i++;for(j=p;j<max;j++,i++){b[i]=a[j];}}else{i++;}}}for(i=min2;i<max;i++)//整理排序后的数组{a[i]=b[i];}
}

通过计算得到人数最多的那个时间段,并输出

重要参数

  • start【】:就餐开始的时间点
  • finish【】:就餐结束的时间点
  • M:学生人数
  • N:就餐时间段的最大值
  • min:数组头的下标
  • c【】:出现的所有时间点的有序集合
  • len:出现的所有时间点的有序集合的长度
  • num【】:所有时间点,对应每个时间点进出的人数
  • data【】:计算每个时间点的人数
  • maxtime【】【】:将时间点化为一个时间段进行存储的数组
  • len2:maxtime的界限值(即个数)
  • maxtime2【】【】:存储人数最多的最大时间段
    算法思路
  • 首先复制一下start【】和finish【】数组,并对其进行排序,并且合并start【】和 finish【】数组到一个新的数组里,为其排序,之后再将对合并后的数组去重。
for(i=0;i<M;i++)//复制start和finish数组{a1[i]=start[i];a2[i]=finish[i];}merge(a1,start,min,M);//排序start数组merge(a2,finish,min,M);//排序finish数组for(j=0,i=M;j<M;i++,j++)//将start数组和finish数组合并{a1[i]=finish[j];}merge(a1,a2,min,2*M);//排序得到后的数组i=0;j=0;c[j]=a2[i];//第一位赋值i++;while(i<2*M)//得到start和finish中出现的所有时间点,且不重复出现,并且有序{if(c[j]!=a2[i]){j++;c[j]=a2[i];}i++;}len=j+1;c[len]=c[len-1]+1;//多腾一个空间为后续计算时间段人数准备len++;
  • 计算哪些时间点有人进出,并且每个时间点进出的人数为多少,存在num【】数组里,代码中有体现。
for(i=0,j=0,k=0;i<2*M;i++)//计算哪个时间点有人进出{while(c[i]==start[j]&&j<M){num[i]++;j++;}while(c[i]==finish[k]&&k<M){num[i+1]--;k++;}}
  • 计算每个时间点的人数并寻找时间点人数最多的时间点,并记录
for(i=1;i<len;i++)//计算每个时间点的人数{data[i]=num[i]+data[i-1];}for(i=0;i<len;i++)//寻找时间点人数最多的是多少人{if(maxnum<=data[i]){maxnum=data[i];}}for(i=0,j=0;i<len;i++)//记录时间点人数最多的时间点{if(data[i]==maxnum){maxtime[j][0]=c[i];maxtime[j][1]=c[i];j++;}}
  • 对最大的时间点进行合并简化,这里要考虑多种情况
    while(j+1<len2&&i<M)//判断是否在一个时间点到另一个时间点都是最大人数{if(len2==1){break;}if(maxtime[j][1]<finish[i])//该时间点没人选择为就餐结束的时间点{maxtime2[k][0]=maxtime2[k][0];maxtime2[k][1]=maxtime[j+1][1];j++;}if(maxtime[j][1]==finish[i]&&maxtime2[k][0]!=0&&maxtime[j+1][1]!=0)//该时间点有人为就餐结束的时间点{i++;k++;j++;maxtime2[k][0]=maxtime[j][0];maxtime2[k][1]=maxtime[j][1];}else if(maxtime[j][1]>=finish[i]){i++;}}len3=k+1;memset(maxtime,0,sizeof(maxtime));//初始化一个数组i=0;j=0;maxtime[j][0]=maxtime2[i][0];maxtime[j][1]=maxtime2[i][1];for(i=0;i+1<len3;)//对得到的就餐人数最大的时间点再次进行计算简化{if(len3==1){break;}if(maxtime2[i][1]-maxtime2[i+1][0]==-1)//相邻天数合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];i++;}else if(maxtime2[i][1]-maxtime2[i+1][0]==0)//同一天合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];i++;}else if(maxtime2[i+1][0]!=0)//不合并,向后移动一位{j++;i++;maxtime[j][0]=maxtime2[i][0];maxtime[j][1]=maxtime2[i][1];if(maxtime2[i][1]-maxtime2[i+1][0]==-1)//相邻天数合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];}else if(maxtime2[i][1]-maxtime2[i+1][0]==0)//同一天合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];}}}

这个函数的源代码


//对起始时间和终止时间进行排序,并计算人数最多的时间void sort(int start[], int finish[], int M, int N,int data[])
{int i,j,k;int min=0,len=0,len2=0,len3=0;int maxnum=0;for(i=0;i<M;i++)//复制start和finish数组{a1[i]=start[i];a2[i]=finish[i];}merge(a1,start,min,M);//排序start数组merge(a2,finish,min,M);//排序finish数组for(j=0,i=M;j<M;i++,j++)//将start数组和finish数组合并{a1[i]=finish[j];}merge(a1,a2,min,2*M);//排序得到后的数组i=0;j=0;c[j]=a2[i];//第一位赋值i++;while(i<2*M)//得到start和finish中出现的所有时间点,且不重复出现,并且有序{if(c[j]!=a2[i]){j++;c[j]=a2[i];}i++;}len=j+1;c[len]=c[len-1]+1;//多腾一个空间为后续计算时间段人数准备len++;for(i=0,j=0,k=0;i<2*M;i++)//计算哪个时间点有人进出{while(c[i]==start[j]&&j<M){num[i]++;j++;}while(c[i]==finish[k]&&k<M){num[i+1]--;k++;}}data[0]=num[0];for(i=1;i<len;i++)//计算每个时间点的人数{data[i]=num[i]+data[i-1];}for(i=0;i<len;i++)//寻找时间点人数最多的是多少人{if(maxnum<=data[i]){maxnum=data[i];}}for(i=0,j=0;i<len;i++)//记录时间点人数最多的时间点{if(data[i]==maxnum){maxtime[j][0]=c[i];maxtime[j][1]=c[i];j++;}}len2=j;i=0;j=0;k=0;maxtime2[k][0]=maxtime[k][0];maxtime2[k][1]=maxtime[k][1];while(j+1<len2&&i<M)//判断是否在一个时间点到另一个时间点都是最大人数{if(len2==1){break;}if(maxtime[j][1]<finish[i])//该时间点没人选择为就餐结束的时间点{maxtime2[k][0]=maxtime2[k][0];maxtime2[k][1]=maxtime[j+1][1];j++;}if(maxtime[j][1]==finish[i]&&maxtime2[k][0]!=0&&maxtime[j+1][1]!=0)//该时间点有人为就餐结束的时间点{i++;k++;j++;maxtime2[k][0]=maxtime[j][0];maxtime2[k][1]=maxtime[j][1];}else if(maxtime[j][1]>=finish[i]){i++;}}len3=k+1;memset(maxtime,0,sizeof(maxtime));//初始化一个数组i=0;j=0;maxtime[j][0]=maxtime2[i][0];maxtime[j][1]=maxtime2[i][1];for(i=0;i+1<len3;)//对得到的就餐人数最大的时间点再次进行计算简化{if(len3==1){break;}if(maxtime2[i][1]-maxtime2[i+1][0]==-1)//相邻天数合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];i++;}else if(maxtime2[i][1]-maxtime2[i+1][0]==0)//同一天合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];i++;}else if(maxtime2[i+1][0]!=0)//不合并,向后移动一位{j++;i++;maxtime[j][0]=maxtime2[i][0];maxtime[j][1]=maxtime2[i][1];if(maxtime2[i][1]-maxtime2[i+1][0]==-1)//相邻天数合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];}else if(maxtime2[i][1]-maxtime2[i+1][0]==0)//同一天合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];}}}len2=j+1;printf("Result:\n");for(j=0;j<len2;j++)//打印数据{printf("%d %d\n",maxtime[j][0],maxtime[j][1]);}
}

整个源代码

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "string.h"#define MAX 200002int data[MAX];
int start[MAX], finish[MAX]; //分别存储起始时间和终止时间
int maxtime[MAX][2]={0},maxtime2[MAX][2]={0};
int a1[MAX]={0},a2[MAX]={0},c[MAX]={0},num[MAX]={0};//录入学生登记的时间段,并判断输入是否合法
void registration(int start[], int finish[], int M, int N)
{int i;printf("Please enter the expected time period for each student in turn: \n");for (i = 0; i < M; i++)//for循环进行输入{printf("The expected period of time for %d students: \n", i + 1);scanf("%d", &start[i]);scanf("%d", &finish[i]);if(start[i]<0||finish[i]>N)//排除非法输入{assert(0);}}
}void merge(int a[],int b[],int min,int max)//归并排序
{int mid,p;//mid为数组的中间位置,p为从中间位置开始的指针int min2;//记录了数组最小的位置int i,j;min2=min;//min为从最小位置开始的指针if((max-min)<=1)//如果数组为1则return{return;}mid=(max+min)/2;//计算中间位置p=mid;merge(a,b,min,mid);//向中间位置的左边递归merge(a,b,mid,max);//向中间位置的右边递归for(i=min;i<max;)//开始归并排序{if(a[min]>a[p])//左边大于右边{b[i]=a[p];p++;if(p==max)//判断是否排序完成{i++;for(j=min;j<mid;j++,i++){b[i]=a[j];}}else{i++;}}if(a[min]<=a[p])//右边大于左边{b[i]=a[min];min++;if(min==mid)//判断是否排序完成{i++;for(j=p;j<max;j++,i++){b[i]=a[j];}}else{i++;}}}for(i=min2;i<max;i++)//整理排序后的数组{a[i]=b[i];}
}//对起始时间和终止时间进行排序,并计算人数最多的时间void sort(int start[], int finish[], int M, int N,int data[])
{int i,j,k;int min=0,len=0,len2=0,len3=0;int maxnum=0;for(i=0;i<M;i++)//复制start和finish数组{a1[i]=start[i];a2[i]=finish[i];}merge(a1,start,min,M);//排序start数组merge(a2,finish,min,M);//排序finish数组for(j=0,i=M;j<M;i++,j++)//将start数组和finish数组合并{a1[i]=finish[j];}merge(a1,a2,min,2*M);//排序得到后的数组i=0;j=0;c[j]=a2[i];//第一位赋值i++;while(i<2*M)//得到start和finish中出现的所有时间点,且不重复出现,并且有序{if(c[j]!=a2[i]){j++;c[j]=a2[i];}i++;}len=j+1;c[len]=c[len-1]+1;//多腾一个空间为后续计算时间段人数准备len++;for(i=0,j=0,k=0;i<2*M;i++)//计算哪个时间点有人进出{while(c[i]==start[j]&&j<M){num[i]++;j++;}while(c[i]==finish[k]&&k<M){num[i+1]--;k++;}}data[0]=num[0];for(i=1;i<len;i++)//计算每个时间点的人数{data[i]=num[i]+data[i-1];}for(i=0;i<len;i++)//寻找时间点人数最多的是多少人{if(maxnum<=data[i]){maxnum=data[i];}}for(i=0,j=0;i<len;i++)//记录时间点人数最多的时间点{if(data[i]==maxnum){maxtime[j][0]=c[i];maxtime[j][1]=c[i];j++;}}len2=j;i=0;j=0;k=0;maxtime2[k][0]=maxtime[k][0];maxtime2[k][1]=maxtime[k][1];while(j+1<len2&&i<M)//判断是否在一个时间点到另一个时间点都是最大人数{if(len2==1){break;}if(maxtime[j][1]<finish[i])//该时间点没人选择为就餐结束的时间点{maxtime2[k][0]=maxtime2[k][0];maxtime2[k][1]=maxtime[j+1][1];j++;}if(maxtime[j][1]==finish[i]&&maxtime2[k][0]!=0&&maxtime[j+1][1]!=0)//该时间点有人为就餐结束的时间点{i++;k++;j++;maxtime2[k][0]=maxtime[j][0];maxtime2[k][1]=maxtime[j][1];}else if(maxtime[j][1]>=finish[i]){i++;}}len3=k+1;memset(maxtime,0,sizeof(maxtime));//初始化一个数组i=0;j=0;maxtime[j][0]=maxtime2[i][0];maxtime[j][1]=maxtime2[i][1];for(i=0;i+1<len3;)//对得到的就餐人数最大的时间点再次进行计算简化{if(len3==1){break;}if(maxtime2[i][1]-maxtime2[i+1][0]==-1)//相邻天数合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];i++;}else if(maxtime2[i][1]-maxtime2[i+1][0]==0)//同一天合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];i++;}else if(maxtime2[i+1][0]!=0)//不合并,向后移动一位{j++;i++;maxtime[j][0]=maxtime2[i][0];maxtime[j][1]=maxtime2[i][1];if(maxtime2[i][1]-maxtime2[i+1][0]==-1)//相邻天数合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];}else if(maxtime2[i][1]-maxtime2[i+1][0]==0)//同一天合并{maxtime[j][0]=maxtime[j][0];maxtime[j][1]=maxtime2[i+1][1];}}}len2=j+1;printf("Result:\n");for(j=0;j<len2;j++)//打印数据{printf("%d %d\n",maxtime[j][0],maxtime[j][1]);}
}int main()
{int N, M; //分别存储时间的段数和学生的个数printf("Number of periods of time:  ");scanf("%d", &N);printf("Number of students:  ");scanf("%d", &M);getchar();registration(start, finish, M, N); //录入学生登记的时间段sort(start, finish, M, N, data);         //对起始时间和终止时间进行排序return 0;
}

数据结构实验——就餐人数最多的时间段相关推荐

  1. 数据结构实验六 综合数据处理

    广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼416A)     2019年6月14日 学院 计算机科学与教育软件学院 年级.专业.班 计算机大类 144班 姓名 学号 实验课程名称 ...

  2. sdut 2135 数据结构实验之队列一:排队买饭

    数据结构实验之队列一:排队买饭 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Discuss Problem Descriptio ...

  3. 数据结构实验:哈希表

    数据结构实验:哈希表 题目描述 在n个数中,找出出现次数最多那个数字,并且输出出现的次数.如果有多个结果,输出数字最小的那一个. 输入 单组数据,第一行数字n(1<=n<=100000). ...

  4. 数据结构实验之排序七:选课名单

    数据结构实验之排序七:选课名单 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 随着学校规模 ...

  5. 数据结构实验公交车系统

    数据结构实验公交车系统(完整代码私信) 1.查询公交车信息 2.查询站点信息 3.查询两个站点之间的路线(最多一次换乘) 4.添加.删除.修改公交车,站点,路线 创建4个文本文档(即txt) rout ...

  6. 数据结构实验之排序四:寻找大富翁__咳咳咳,还魂篇!!

    数据结构实验之排序四:寻找大富翁 Time Limit: 200MS  Memory Limit: 512KB Submit  Statistic Problem Description 2015胡润 ...

  7. 计算机科学与技术考研人数多,考研报考人数最多的专业 计算机科学与技术

    考研报考人数最多的专业计算机科学 与技术 计算机科学与技术 学科:工学 门类:电气信息类 专业名称:计算机科学与技术 业务培养目标:本专业培养具有良好的科学素养,系统地.较好地掌握计算机科学与技术包括 ...

  8. 数据结构实验之排序四:寻找大富翁 SDUT

    数据结构实验之排序四:寻找大富翁 SDUT Time Limit: 200 ms Memory Limit: 512 KiB Submit Statistic Problem Description ...

  9. 数据结构实验入门:学生成绩统计排序系统

    笔者最近在学校开始学习数据结构,这门课程作为计算机专业的最核心课程需要重点掌握,下面是数据结构实验课上的第一次作业内容,笔者在这里分享一下自己的想法和见解 一.实验内容 设计程序实现统计一个班的学生成 ...

  10. 数据结构实验报告(一)

    数据结构实验报告(一) 一.实验名称 实验一  线性表的基本操作实现及其应用 二.实验目的 1.熟练掌握线性表的结构特点,掌握顺序表的基本操作. 2.巩固 C++相关的程序设计方法与技术. 3.学会使 ...

最新文章

  1. Objective-C自动生成文档工具:appledoc
  2. appium-在页面点击一下处理(一般处理提示蒙层)
  3. ASP NET Core --- HTTP 翻页、过滤、排序
  4. java nio.2群发_JAVA NIO TCP SOCKET 聊天群发
  5. git-创建版本仓库-创建版本-查看版本
  6. (转载)查看Oracle字符集及怎样修改字符集
  7. GitHub项目:自然语言处理领域的相关干货整理
  8. [版本1.11.4已修复]简书安卓UI界面Bug:主界面消失
  9. Python利用shelve模块设计简单数据库程序
  10. 删除IE浏览器JS缓存
  11. css html颜色,CSS颜色
  12. 矩阵开根号,工作矩阵平方根
  13. 按计算机病毒的传染方式来分类可以分为良性,5、 计算机病毒分为哪几类?传染途径有哪些?...
  14. RCF—用于C++的进程间通讯(1)
  15. php微信支付mch_id参数格式错误,再说一下微信支付踩到的坑 mch_id 参数格式错误...
  16. Word怎么在方框里面打对勾
  17. 如何快速搭建手游平台?
  18. 单例模式破坏单例模式
  19. 脉冲发生器c语言程序,可编程脉冲信号发生器的.doc
  20. 03.服务限流实现方案

热门文章

  1. 给大家推荐一波Python书单,电子版拿走不谢
  2. java时间戳的单位_java – SimpleDateFormat – 解析时间戳,以毫秒为单位
  3. python flink kafka_Flink Kafka 端到端 Exactly-Once 分析
  4. 半监督学习与直推式学习
  5. luminex细胞因子检测
  6. Googgle guava ImmutableCollections
  7. 滴滴入局同城货运,一场闪电战,还是持久战?
  8. ThinkPHP 3.2.3 验证码 (解决图片不显示的问题)
  9. Excel VBA自动填充公式
  10. 聊一聊为什么JAVA只允许单继承