某天,家父加班晚归,在饭桌上感叹工作之不易。我随口一问,问题来源于水果手机出新品的时候,需要将手里的货分配给若干个代理商。每个代理商都提出了需求(某种机型需要多少台),然而因为资源有限,公司给每个代理商设置了一个分配上限(分配给这家代理商的手机总数不能超过上限)。代理商大概有几百家,水果手机按颜色、内存、尺寸也能分出十几种,总库存上千。家父与其伙伴每次都手动分配、调整,有时甚至需要数个小时,十分无奈。
-- Version 0 --
我一看,这不妥妥的
最大流吗,建立一个二部图,一侧表示手机机型,另一侧表示代理商。手机存货量通过源点到手机机型的边控制,代理商上限通过代理商到汇点的边控制,代理商需求用手机机型和代理商间的连边控制,不就可以了吗?
-- Version 1 --
家父便给了我一个以前的任务来测试。当然不到一秒就跑出结果来了。但是,家父指出一个问题,就是 不同代理商的优先级是不一样的 ,配额高的代理商,应该优先分配。
再一看,哟,妥妥的
最小费用最大流啊,给每个流赋一个权重,流向不同的代理商有不同的权重,完美。
-- Version 2 --
家父表示这次的结果能看了许多,但仍然有一个问题:这样分配出来,一个代理商往往会得到特别多的某种机型,而其余机型则一台都得不到,这个在现实中也不太合理。
唔,这次要求流向统一代理商的不同机型尽量均匀啊。这个我没想到特别优雅的解决方案,我只是稍微改了一下算法的实现:在上面的算法中,每一轮计算都会尽可能分配一堆某种手机给同一代理商,于是我改成了每次计算只分配一台,而且在有多种方案时随机选择一种。
这样跑出来的结果就合理多啦!不过效率低了不少,大概得跑半分钟吧。
-- Version 3 --
算法上的改进就没有啦,不过毕竟不能让家父在终端跑程序,所以拿C#撸了个界面,读入某种格式的csv文件,算出结果填到csv里再输出出去(讲道理在Excel里写vba估计也行,不过我之前算法拿C++写的,改C#容易些)。最后从网上抄了个进度条,用户体验max!
从此以后,家父与其伙伴可以在半个小时内解决问题(毕竟还要微调一下,数据录入之类的)。
-- 分割线 --
这个故事告诉我们,学算法还是有用的!
-- 再次分割 --
13年我回高中夏令营演讲的时候,我将 编程 这一技能比喻为信息时代的 驾驶 ,每个人能可以并且应该去学习、掌握。有趣的是,当时收到一份反馈,说驾驶不仅仅是技能,它还可以给人以愉悦之享受。今天回过头来看这个反馈,突然明白了,这种愉悦某种程度上源自于你获得的 操控感 。可巧的是,编程也可以带来极强的操控感。在信息时代,对手中 数据 的操控能力是极为重要的。