《编程之美》1.9:高效率的安排见面会的一个解法
2011-06-14 11:23
387 查看
原题是这样的:
在校园招聘的季节里,为了能让学生们更好地了解微软亚洲研究院各研究组的情况,HR部门计划为每一个研究组举办一次见面会,让各
个研究组的员工能跟学生相互了解和交流(如图1-4所示)。已知有n位学生,他们分别对m个研究组中的若干个感兴趣。为了满足所有学生的要求,HR希望每
个学生都能参加自己感兴趣的所有见面会。如果每个见面会的时间为t,那么,如何安排才能够使得所有见面会的总时间最短?
最简单的办法,就是把m个研究组的见面会时间依次排开,那我们就要用m * t的总时间,我们有10多个研究小组,时间会拖得很长,能否进一步提高效率?
此题的官方解法是将问题转化为一个已知的图的问题:即图的最少着色问题。 但有两点感觉不太好:
一是这个问题的转换感觉角度有些大,不够平滑。 如果此前没听过图的最少着色问题,那么是怎么也不可能想到这儿的。
二是关于此题的分析与解法讲解非常笼统,尤其是解法,寥寥数语就完了 - 我觉得是没有把问题讲清楚的 - 虽然读者自己可以阅读“
图的最少着色问题”来获得更多的了解,但既然此题作为单独的一题存在,我觉得还是讲清楚点好。
另外,自己思考了一下,觉的此题不转化成图的最少着色问题,通过简单的递归,应该也是可以实现的。
那么,我们可以按以下方式,逐个考虑见面会:
对于见面会A,因为其前面没有见面会,略过;
对于见面会B,考虑它和其前面的见面会A是否冲突,如果不冲突,就将B和A合并,继续考虑C;而另外还有一个分支是不管是否冲突,此时不做合并,直接考虑C;
对于见面会C,考虑它和其前面的见面会A,B是否冲突,第一个分支是如果与A不冲突,
就将C和A合并,继续考虑D;第二个分支是如果与B不冲突,
就将C和B合并,继续考虑D;而第三格分支还是不做任何合并,直接考虑D
按此规则继续对下一个见面会做考察
当对最后一个招聘会做完考察后,记下其时间,程序然后递归回溯,会由其他分支继续考察最后一个招聘会,比较并记录最短的那个,这样,当所有的分支都考察过后,记录的那个最短时间就是全局最短的时间了。
来表示,行表示见面会,列表示学生,数组元素表示某学生是否参加该见面会。
递归过程用当前考虑的见面会控制,当最后一个见面会考虑完之后,就得到一个候选解,程序然后回溯,从另一分支再次进入,考虑最后一个见面会,与之前的候选解比较,保存较优的那个:候选解包括见面会时间与当前的具体安排
在校园招聘的季节里,为了能让学生们更好地了解微软亚洲研究院各研究组的情况,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]来表示,行表示见面会,列表示学生,数组元素表示某学生是否参加该见面会。
递归过程用当前考虑的见面会控制,当最后一个见面会考虑完之后,就得到一个候选解,程序然后回溯,从另一分支再次进入,考虑最后一个见面会,与之前的候选解比较,保存较优的那个:候选解包括见面会时间与当前的具体安排
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] , 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)
原帖地址:/article/4969827.html 《编程之美》:豆瓣 ,微博
相关文章推荐
- 《编程之美》1.9:高效率的安排见面会的一个解法
- 《编程之美》读书笔记05: 1.9 高效率的安排见面会
- 编程之美:1.9高效率安排见面会 图的m着色问题 回溯法
- 编程之美:第一章 1.9高效率地安排见面会
- 编程之美--1.9高效率的安排见面会(解法二python)
- 编程之美1.9——高效率地安排见面会
- 1.9 高效率的安排见面会
- 编程之美-高效率的安排见面会
- 编程之美:高效率地安排见面会
- 编程之美读书笔记_1.9 高效率的安排见面会
- 编程之美-高效率安排见面会的方法整理
- 高效率安排见面会问题(比编程之美的解法复杂度低n-1个数量级)
- 读书笔记之编程之美 - 1.9 高效率地安排见面会
- flyinghearts《编程之美》读书笔记连载(6)-高效率安排见面会
- 编程之美----高效率地安排见面会----贪心策略
- 编程之美-----高效率地安排见面会
- 高效率的安排见面会问题
- 第1章 游戏之乐——高效率地安排见面会
- 编程之美读书笔记之-高效率的安排见面会
- 高效率地安排见面会