原题是这样的:

在校园招聘的季节里,为了能让学生们更好地了解微软亚洲研究院各研究组的情况,HR部门计划为每一个研究组举办一次见面会,让各个研究组的员工能跟学生相互了解和交流(如图1-4所示)。已知有n位学生,他们分别对m个研究组中的若干个感兴趣。为了满足所有学生的要求,HR希望每个学生都能参加自己感兴趣的所有见面会。如果每个见面会的时间为t,那么,如何安排才能够使得所有见面会的总时间最短? 最简单的办法,就是把m个研究组的见面会时间依次排开,那我们就要用m * t的总时间,我们有10多个研究小组,时间会拖得很长,能否进一步提高效率?

此题的官方解法是将问题转化为一个已知的图的问题:即图的最少着色问题。 但有两点感觉不太好:

  • 一是这个问题的转换感觉角度有些大,不够平滑。 如果此前没听过图的最少着色问题,那么是怎么也不可能想到这儿的。
  • 二是关于此题的分析与解法讲解非常笼统,尤其是解法,寥寥数语就完了 - 我觉得是没有把问题讲清楚的 - 虽然读者自己可以阅读“ 图的最少着色问题”来获得更多的了解,但既然此题作为单独的一题存在,我觉得还是讲清楚点好。

另外,自己思考了一下,觉的此题不转化成图的最少着色问题,通过简单的递归,应该也是可以实现的。

思路分析

已知有n位学生,m个见面会,且每个学生可以选择参加任意多个见面会。我们的目的是在没有冲突的情况下把某几个见面会的时间重叠起来,同时开。何为冲突,比如学生甲参加了见面会A与B,那么A与B就是冲突的,因为如果同时开的话,学生甲必然要放弃一个。

那么,我们可以按以下方式,逐个考虑见面会:

  • 对于见面会A,因为其前面没有见面会,略过;
  • 对于见面会B,考虑它和其前面的见面会A是否冲突,如果不冲突,就将B和A合并,继续考虑C;而另外还有一个分支是不管是否冲突,此时不做合并,直接考虑C;
  • 对于见面会C,考虑它和其前面的见面会A,B是否冲突,第一个分支是如果与A不冲突, 就将C和A合并,继续考虑D;第二个分支是如果与B不冲突, 就将C和B合并,继续考虑D;而第三格分支还是不做任何合并,直接考虑D
  • 按此规则继续对下一个见面会做考察
  • 当对最后一个招聘会做完考察后,记下其时间,程序然后递归回溯,会由其他分支继续考察最后一个招聘会,比较并记录最短的那个,这样,当所有的分支都考察过后,记录的那个最短时间就是全局最短的时间了。

代码

  • 输入数据可以用一个二维数组input[m][n]来表示,行表示见面会,列表示学生,数组元素表示某学生是否参加该见面会。
  • 递归过程用当前考虑的见面会控制,当最后一个见面会考虑完之后,就得到一个候选解,程序然后回溯,从另一分支再次进入,考虑最后一个见面会,与之前的候选解比较,保存较优的那个:候选解包括见面会时间与当前的具体安排
View Code

1 #include <iostream>
2 #include <list>
3 #include <vector>
4
5  using namespace std;
6
7  // If 2 recruiting meetings are conflicting
8  bool IsConflict(const vector<bool>& v1, const vector<bool>& v2)
9 {
10 for(int i = 0; i < v1.size(); ++i)
11 {
12 if(v1[i] && v2[i]) return true;
13 }
14 return false;
15 }
16
17  // merge 2 recruiting meetings: v2 will be held at the same time of v1
18  void Merge(vector<bool>& v1, const vector<bool>& v2)
19 {
20 for(int i = 0; i < v1.size(); ++i)
21 {
22 v1[i] = v1[i] || v2[i];
23 }
24 }
25
26  // input: input[m][n], 2d array to represents students' selection of meetings. row stands for meetings, column stands for students,
27 // and array value stands for if a student select a meeting
28 // next: The meeting to check
29 // curTime: Time required so far
30 // curArrangement: record the information of which meeting is merged with another meeting
31 // best[output]:The best time
32 // bestArrangement[output] : The best arragement
33 void ArrangeRecruitings(vector<vector<bool> >& input, int next, int& curTime, vector<list<int> >& curArrangement, int& bestTime, vector<list<int> >& bestArrangement)
34 {
35 int m = input.size();
36 // base cases
37 if(next >= m)
38 {
39 // Save the best one
40 if(curTime < bestTime)
41 {
42 bestTime = curTime;
43 bestArrangement = curArrangement;
44 }
45
46 return;
47 }
48 else
49 {
50 // recursive cases
51 for(int i = 0; i <= next; ++i)
52 {
53
54 if(curArrangement[i].empty()) continue; // if already merged with other ones, just skip it
55
56 if (!IsConflict(input[i], input[next]))
57 {
58
59 // update the status
60 vector<bool> bkI = input[i];
61 Merge(input[i], input[next]);
62
63 curArrangement[next].pop_back();
64 curArrangement[i].push_back(next);
65
66 // Consider next one after merge
67 ArrangeRecruitings(input, next+1, curTime, curArrangement, bestTime, bestArrangement);
68
69 // restore the status
70 curArrangement[i].pop_back();
71 curArrangement[next].push_back(next);
72
73 input[i] = bkI;
74 }
75 }
76
77 // Consider next one without any merge
78 ArrangeRecruitings(input, next+1, ++curTime, curArrangement, bestTime, bestArrangement);
79
80 }
81 }
82
83
84 int main()
85 {
86 // 1. Initializing
87 int m = 3;
88 int n = 4;
89
90 vector<vector<bool> > input(m, vector<bool>(n, false));
91
92 input[0][0] = true;
93 input[0][1] = true;
94
95 input[1][1] = true;
96 input[1][2] = true;
97
98 input[2][2] = true;
99 input[2][3] = true;
100
101 //input[0][2] = true;
102
103 int curTime = 1;
104 int bestTime = m+1;
105 vector<list<int> > curArrangement(m);
106 vector<list<int> > bestArrangement(m);
107 for(int i = 0; i < m; ++i) curArrangement[i].push_back(i);
108
109 // 2. Solve
110 ArrangeRecruitings(input, 1, curTime, curArrangement, bestTime, bestArrangement);
111
112 // 3. Output the result
113 cout << "Totoal Time: " << bestTime << endl;
114 for(int i = 0; i < m; ++i)
115 {
116 cout << i << "): ";
117 if(bestArrangement[i].empty())
118 {
119 cout << "none" << endl;
120 continue;
121 }
122 for(list<int>::const_iterator it = bestArrangement[i].begin(); it != bestArrangement[i].end(); ++it)
123 cout << *it << "-";
124
125 cout << endl;
126 }
127 }

复杂度分析

可以注意到,我们需要逐个考虑见面会,一共是m个;而在考虑第i个见面会时,我们最多可能会产生出i个分支,不难看出,总问题的规模为m!;而产生每个分支时需要做的计算是O(n)的冲突检测与合并,于是,整个的算法复杂度为:O(m! * n)

《编程之美》1.9:高效率的安排见面会的一个解法相关推荐

  1. 编程之美读书笔记之-高效率的安排见面会

    问题一: n个同学,分别对m个招聘见面会感兴趣.为了满足所有学生的要求,hr希望让每个同学都能参加自己所有感兴趣的见面会.然后每个见面会的时间为t.问如何安排见面会能够使得所有见面会总的时间最短. 建 ...

  2. 编程之美 - 读书笔记 - 卖书折扣问题的贪心解法

    <编程之美>读书笔记(四):卖书折扣问题的贪心解法 每 次看完<编程之美>中的问题,想要亲自演算一下或深入思考的时候,都觉得时间过得很快,动辄一两个小时,如果再把代码敲一遍的话 ...

  3. 面试难,应聘难,好工作,今安在?——《编程之美——微软技术面试心得》为你探路!即将上市,敬请关注!

    这本书是我目前所见到的优秀面试试题的最全集,包含大量有趣且有启发性的题目,一方面对于学生的指导意义重大,另一方面,即使对于我们这些已经工作的人来说,也不失为一本充满智慧与趣味的好书."    ...

  4. java 编程之美_《编程之美—微软技术面试心得》PDF 下载

    第1章 游戏之乐--游戏中碰到的题目 1.1 让CPU占用率曲线听你指挥 1.2 中国象棋将帅问题 1.3 一摞烙饼的排序 1.4 买书问题 1.5 快速找出故障机器 1.6 饮料供货 1.7 光影切 ...

  5. 面试难,应聘难,好工作,今安在?——《编程之美——微软技术面试心得》为你探路!即将上市,敬请关注!...

    这本书是我目前所见到的优秀面试试题的最全集,包含大量有趣且有启发性的题目,一方面对于学生的指导意义重大,另一方面,即使对于我们这些已经工作的人来说,也不失为一本充满智慧与趣味的好书." -- ...

  6. 精选的一些《编程之美》相关资料

    又要到一年的招聘季了,肯定又有很多人开始啃<编程之美>了吧.这本书从开阔视野的角度来说很好,不过限于篇幅,有的问题并没有讲清楚(甚至问题叙述模棱两可.被标榜为"鼓励同面试官交流以 ...

  7. 让多核CPU占用率曲线听你指挥(Windows实现)——《编程之美》1.1学习笔记

    让多核CPU占用率曲线听你指挥--<编程之美>1.1学习笔记 Problem: 写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率.有以下几种情况: ...

  8. 编程之美-翻烙饼问题

    翻烙饼问题 前言 翻烙饼问题是非常经典的问题,星期五的晚上,一帮同事在希格玛大厦附近的"硬盘酒吧"多喝了几杯.程序员多喝了几杯之后谈什么呢?自然是算法问题.有个同事说: " ...

  9. 《编程之美》相关参考资料

    转载自:https://blog.csdn.net/wuyuegb2312/article/details/9896831 为了便于查阅,也为了方便后人不必在搜索上浪费时间,我把比较有价值的文章的链接 ...

最新文章

  1. vscode 中搭建Vue.js
  2. poj 3038 Children of the Candy Corn bfs dfs
  3. ST17H26 SDK中宏定义注意事项
  4. Linux一键安装Lnmp
  5. redis 安装使用
  6. 通过自定义配置实现插件式设计
  7. 使用deploy命令上传jar到私有仓库
  8. dom选择方法的区别
  9. sonarqube代码检核工具安装
  10. PTA10、统计字符个数 (10 分)
  11. java流对象_Java对象流的使用
  12. OpenCV初探 —— VS2019配置环境
  13. “我是技术总监,你为毛总问我技术细节?”
  14. H5网站模板——前台和后台
  15. 软件测试——白盒测试
  16. 如何根据图片找到图中的地点
  17. 大学生职业生涯规划书性格特征_大学生职业生涯规划书自我分析范文
  18. 元宇宙、区块链和潘家园
  19. 容量 Byte、KB、MB、GB、TB、PB、EB、ZB、YB、NB、DB、CB、XB
  20. 数字图像处理实验(七)| 形态学图像处理{生成结构元素strel、腐蚀运算imerode、膨胀运算imdilate、开运算imopen、闭运算imclose}(附代码和实验截图、汉字视力表项目、总结)

热门文章

  1. c语言两点间距离_数字图像处理|P5第二章 数字图像基础第四节像素间的基本关系...
  2. 利用函数重载编写函数max_c++笔记(函数重载)
  3. grub2配置原理分析
  4. 计算机考研去哪个城市,2019计算机考研:考研热门城市院校排名
  5. Ansible Synchronize
  6. python log
  7. 在过程中要正式批准可交付成果_PMP模拟考试一(200题中文版)
  8. 4安全框_压花玻璃与安全玻璃有哪些特点?玻璃隔断的介绍
  9. 基于物联网的新型智能家居控制系统设计
  10. CVE-2020-1472复现与完整利用