某题目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));