某题目1:
某公司在北京和上海各有 N 个员工,比如北京有10员工,员工编号 1 到 10,在上海有10个员工,编号 11 到 20.
公司的所有项目,都是2个人的team,一个来自北京,一个来自上海
每个人可能参与多个项目,但同一个team,不会参与多个项目
年终了,CEO要开总结会,要求每个项目都要来至少 1 个代表,来总结项目。
由于经费有限,需要写一个程序,计算出最少的人(但每个项目都要来人),至少打印出一组数据
测试样例:
1, 16
1, 13
1, 15
2, 19
3, 16
5, 15
7, 13
7, 14
8, 14
一组可能的输出结果: 2, 13, 14, 15, 16
数学模型:
1. 每个pair在坐标轴上可以看作一个点
2. 水平或者竖直方向能连线的点,都算在一个group内,把所有点划分成多个group
比如下图中被划分为2个group
3. 一个group内,横向数线的条数,纵向数线的条数,哪个条数少就取哪个方向,所有该方向线的坐标值,就是这个group的最少组合
Group 1横向数1条线,纵向1条线,就取横向坐标 2
Group 2横向数5条线,纵向4条线,就取纵向坐标 13, 14, 15, 16
4. 把所有group计算出的组合汇总到一起
得到 2, 13, 14, 15, 16
代码:
data = [ [1, 16], [1, 13], [1, 15], [2, 19], [3, 16], [5, 15], [7, 13], [7, 14], [8, 14] ]; MAX = 10;//坐标轴上限,即一个地点的最大人数 /* convert arr to map: { 1: [13, 15, 16], 2: [19], 3: [16], 5: [15], 7: [13, 14], 8: [14], 13: [1, 7], 14: [7, 8], 15: [1, 5], 16: [1, 3], 19: [2] }*/ function generateMap(arr) { return reduce(function(o, pair) { var k = pair[0], v = pair[1]; if(!o[k]) o[k] = []; o[k].push(v); return o; }, {}, arr); } map_X = generateMap(data);//根据横坐标生成map_X map_Y = generateMap(flip(data));//根据纵坐标生成map_Y map = apply(map_X, map_Y);//合并为map,内容如上 function apply(dest, src) { for(var x in src) dest[x] = src[x]; return dest; } //从map生成group数组, 结构和上一篇很像, 因为都是从一个点出发寻找所有路径 function map_2_groups(map) { function makeGroup(el) { function findRoutes(route) { function notVisited(el) { return !member(route.path, el); } function continueRoute(el) { return findRoutes({ path: route.path.concat(el), current: el }); } var rest = filter(notVisited, map[route.current]); if(rest.length === 0) { return route.path; } else { return flatten(_map(continueRoute, rest));//由于上面用到了map变量,所以map函数改成_map } } var r = findRoutes({ path: [el], current: el }); return r; } function isInGroups(groups, el) { return member(flatten(groups), el); } var gs = []; forObjKey(map, function(k) { if(!isInGroups(gs, k)) { gs.push(unique(makeGroup(parseInt(k, 10)))); } }); return gs; } function forObjKey(o, fn) { for(var x in o) fn(x); } /* groups = [ [1, 16, 3, 13, 7, 14, 8, 15, 5], [2, 19] ] */ groups = map_2_groups(map);//得到所有group function isX(x) { return x < MAX; } function isY(y) { return y >= MAX; } function minimalGroup(group) { var xy = reduce(function(base, el) { base[isX(el) ? 0 : 1].push(el); return base; }, [[],[]], group); //取x或y方向线条数较小,并返回该方向的所有坐标值 return xy[0].length > xy[1].length ? xy[1] : xy[0]; } minGroup = flatten(_map(minimalGroup, groups));