中兴捧月的某道预赛题

一直忙着折腾别的事,把预算给放一边了。幸好,离截至时间前20分钟提交了。选了一道简单的布雷,还有一个家访问题。布雷的程序就不拿出来说了,二十行不到,算法也简单。就在这说下教师家访问题吧。 题目是这样滴。

输入文件:student.txt distance.txt
你是小学某班主任,需要安排周六进行家访。于是打电话与家长联系,他们表示虽然比较忙,但还是会为你抽出一点时间。
由于有些家长时间上有冲突,并且一天内不能拜访所有家长,你需要一个程序安排一天的工作,使得你可以拜访最多的家长。注意, 如果与某个家长见面,拜访时间不得少于45分钟(M),否则可能引起家长不满意。另外从一个家长到另外一个家长需要花费一些时间。

Input1: student.txt
输入包括多个测试数据,每个测试数据开头是一个整数n(1<=n<=40),表示家长总数。接下来n行每行包括三个正整数m、s、t。m表 示家长的序号,s、t分别表示该家长空闲时间段的起始时间和终止时间,s小于t。注意两个数字的最后两位表示分钟。
比如1645 表示16时45分
样本如下:
6
1 800 1100
2 800 900
3 845 1000
4 1300 1400
5 1345 1800
6 1500 1700

Input2: distance.txt
第一行为 家长总数
随后为一个二维表格,记录每2个用户之间的距离。第二行和第一列数据为家长顺序编号。其他数据为2个家长之间的距离。
样本如下:
6
0 1 2 3 4 5 6
1 0 1 2 4 3 1
2 1 0 3 5 3 2
3 2 3 0 6 1 3
4 4 5 6 0 4 14
5 3 3 1 4 0 15
6 1 2 3 14 15 0

Output:
拜访的家长总数
拜访的家长的序号和开始结束时间

1 选用的数据结构

1.1 各家长空闲时间

因为每个测试样本家长的数量不定,所以使用链表结构对各家长进行存储。链表中每个结点代表一位家长。结构如下:
其中id为加家长序号,t_begin为家长空闲时间段的起始时间,t_end为空闲时间段的结束时间。

1.2 各家长之间的距离矩阵 

由于家长之间的距离矩阵为N阶对称矩阵,且主对角元素为0,所以可将其压缩为(N-1)阶,并只保存其小三角部分。再加上各样本中家长数目不定,所以采用动态数组进行保存。假设家长数目为:n = stuCount ,则需要分配的存储空间为:k=(stuCount-1)*stuCount/2;

1.3 确定访问的家长队列

程序将确定要访问的家长放入一队列中,数据结构为
程序将确定要访问的家长从家长链表中脱离,并加入到访问列队中。此时只需要修改对应家长结点的首尾指针即可,不需要额外分配存储空间。

2 被访家长的选择算法

2.1 遵循的原则

(1)在最短的时间内访问最多的家长;

(2)一般情况下,按照家长空闲起始时间依次访问;所以需要对家长链表按照空闲起始时间升序排列。

(3)如果家长空闲时间较长,比如大于两个最小家访时间(45分钟),则将其安排在靠后位置。比如下列情况:

序号空闲开始时间空闲结束时间
108001200
208050910

则先访问家长2,然后再访问家长1。

(4)对每个家庭访问的结束时间要尽可能早。

2.2 算法实现

(1)以当前t_cur为基准,给出一个待选家长的集合,集合满足:

t_begin > t_cur + t_dis + 45;

其中,t_begin为家长空闲开始时间,t_cur为当前时间,t_dis为从当前家长前进到第二个待选家长所需的路程时间,45为每个家长的最小家访时间。

(2)然后从待选家长集合中,选择出t_end最小,并且(t_end-t_begin)>=45的一个家长进行访问,t_end为家长空闲结束时间。

(3)将家长集合中被访的家长加入被访队列中。

(3)将t_cur当前时间设置为当前的访问结束时间。并将家长链表中t_begin设为t_cur。

(4)继续以当前t_cur为基准,开始下一个集合的选择。

3 程序运行流程

程序从数据文件中读出各组数据进行处理,并将处理结果放入被访队列。如下图所示:

4 函数说明

程序所使用的函数说明如下:

● int InitFamilyList(ifstream &fstu, pfamily &phead);

功能:初始化家长链表

参数:fstu -- 输入文件流对象的引用(本程序中与student.txt文件连接)

phead – 指向家长链表头结点的指针的引用

● void SortFamilyList(pfamily phead, const int &stuCount);

功能:对家长链表排序

参数:phead – 指向家长链表头结点的指针

stuCount – 家长数量的引用

● void DestoryFamilyList(pfamily phead);

功能:删除链表

参数:phead – 指向家长链表头结点的指针

● int InitDistanceArray(int *arr, ifstream &fdist, const int &stuCount);

功能:初始化家长距离矩阵

参数:arr – 指向家长距离矩阵的指针

fdist -- 输入文件流对象的引用(本程序中与distance.txt文件连接)

stuCount – 家长数量的引用

● bool InitResultFamilyQuery(LINKQUEUE *Q);

功能:初始化被访家长队列

参数:Q – 指向被访家长队列的指针

● bool EnFamilyQueue(LINKQUEUE *Q, pfamily p);

功能:将被访家长加入到队列中

参数:Q – 指向被访家长队列的指针

p – 指向某家长链表中某个结点的指针

● void ShowFamilyQueue(LINKQUEUE *Q, const int &visitCount);

功能:显示被访家长队列

参数:Q – 指向被访家长队列的指针

visitCount – 被访家长总数的引用

● void ShowFamilyList(family phead);

功能:显示家长链表内容

参数:phead – 指向家长链表头结点的指针

注意:此函数仅供调试过程中使用,最终的Main.cpp文件中没有对次函数的调用

● void CalculateVisitedFamily(pfamily &phead, int *arr, LINKQUEUE *&Q, int &visitCount);

功能:选择被访家长的核心函数

参数:phead – 指向家长链表头结点的指针的引用

arr – 指向家长距离矩阵的指针

Q – 指向被访家长队列的指针的引用

visitCount – 被访家长总数的引用

其中最重要的函数是最后一个CalculateVisitedFamily,用于安排被访家长,函数定义如下:
注释貌似有点乱。额。其实,没提交上去的版本里的注释,更加非主流,还有我代表月亮消灭你。O(∩_∩)O

5 数据测试

通过数据进行测试,具体数据文件请参见可执行文件目录中的文件。

各组数据分别测试了最简情况、题目给出的样本情况、家长集合的选取、排序极端情况及教师空闲时间段处理以及重复时间段极端情况。

程序运行截图如下:

还有就是源代码包,可是在哪上传呢?没找到地方哦。要的童鞋留下邮箱吧。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值