Indiebard

2016年华为软件精英挑战赛小结

【总结】

这次无缘全国总决赛,主要是因为算法瓶颈所限,无法很好地处理所有规模的数据。听说最后进决赛的队上合赛区第一名用的是遗传算法,感觉很玄乎,打算决赛结束之后请教一发。但是感觉这次比赛所写的代码加起来总共也有2000+行了吧,也有一些值得反思和提炼的部分。

【初赛赛题】

  •  问题定义

给定一个带权重的有向图G=(V,E),V为顶点集,E为有向边集,每一条有向边均有一个权重。对于给定的顶点s、t,以及V的子集V',寻找从s到t的不成环有向路径P,使得P经过V'中所有的顶点(对经过V'中节点的顺序不做要求)。

若不存在这样的有向路径P,则输出无解,程序运行时间越短,则视为结果越优;若存在这样的有向路径P,则输出所得到的路径,路径的权重越小,则视为结果越优,在输出路径权重一样的前提下,程序运行时间越短,则视为结果越优。

说明:

1)图中所有权重均为[1,20]内的整数;

2)任一有向边的起点不等于终点;

3)连接顶点A至顶点B的有向边可能超过一条,其权重可能一样,也可能不一样;

4)该有向图的顶点不会超过600个,每个顶点出度(以该点为起点的有向边的数量)不超过8;

5)V'中元素个数不超过50;

6)从s到t的不成环有向路径P是指,P为由一系列有向边组成的从s至t的有向连通路径,且不允许重复经过任一节点;

7)路径的权重是指所有组成该路径的所有有向边的权重之和。

  • Solution

初赛是每个赛区进36支队至复赛,其中排名前32直接进,后4名由复活赛决出。样例规模从小到大分布,可以针对某种类型的数据范围做针对性的优化。

         对于小数据,总点数不会超过20,直接考虑状态压缩动态规划求出最优解,很好写。

         对于中型数据,关键点数不会超过20,考虑使用A*算法得出最优解,先跑多次dijkstra得出关键点以及中点间两两的距离,之后以所有关键点为状态,跑一遍状态压缩动态规划预处理。

         每次A*搜索的时候,记录一个状态为{当前访问到的点,访问过的点集},最终状态是{终点,包含所有关键点的点集}。对于每个状态,它的估价为:枚举下一次要访问的关键点编号v,估价值为当前点到v的距离加上从v经过所有未访问关键点到终点的估价距离。容易证明这一定是答案的下界,因此用A*可以搜出最优解。

         对于大型数据,仍按中型数据的算法做会出现的问题是:关键点数超过20,状压DP预处理会超时(复杂度O(n^2*2^n))。

因此考虑更换估价函数,对于每个状态,新的估价函数为:从当前访问的点开始依次访问未经过关键点中距离最近的那个点,并求距离和,也就是经典的TSP问题的贪心做法。由于这个估价不是答案的下界,它只能用来启发搜索,因此搜索出的第一个解不一定是最优解,还需要继续搜索,直到程序时间限制为止,可以得出一个较优解。

【复赛赛题】

  •  问题定义

给定一个带权重的有向图G=(V,E),V为顶点集,E为有向边集,每一条有向边均有一个权重。对于给定的顶点s、t,以及V的子集V’和V’’,寻找从s到t的两条不成环的有向路径P’和P’’,使得P’经过V’中所有的顶点,而P’’经过V’’中所有的顶点(对P’经过V’中顶点的顺序以及P’’经过V’’中顶点的顺序不做要求)。

若不同时存在这样的两条有向路径,则输出无解,程序运行时间越短,则视为结果越优; 若同时存在这样的两条有向路径,则输出得到的两条路径,按下列优先级从高到低评价结果优劣:

1、  路径P’和P’’重合的有向边个数越少,则视为结果越优;

2、  在两条路径重合的有向边个数一样的情况下,两条路径权重总和越少,则视为结果越优;

3、  在上述两个指标一样的情况下,程序运行时间越短,则视为结果越优。

说明:

1)图中所有权重均为[1,100]内的整数;

2)任一有向边的起点不等于终点;

3)连接顶点A至顶点B的有向边可能超过一条,其权重可能一样,也可能不一样;

4)该有向图的顶点不会超过2000个,每个顶点出度(以该点为起点的有向边的数量)不超过20;

5)V’和V’’中元素个数均不超过100,交集为空,且不包含起始顶点s和终止顶点t;

6)从s到t的不成环有向路径P是指,P为由一系列有向边组成的从s至t的有向连通路径,且不允许重复经过任一顶点;

7)路径的权重是指所有组成该路径的所有有向边的权重之和(重复边的权重应分别在两条路径中各计算一次)。

  • Solution

如果直接用初赛的方法分别找出两条路径P’和P’’的话,会有两个问题,一个是由于点数增多到了2000个会搜不出来,另一个是由于重合边数太多会难以出较优解。为了解决上述两个问题采用如下的思路:

(1)       使用DLX算法搜出两条路径的初始解。找一条路径的问题可以转化为01精确覆盖问题,只要把每条边选/不选作为一组01变量,每个点经过/不经过作为一组01变量,就能列出精确覆盖问题的方程。但传统的DLX模型解决此类图论问题的时候会产生问题,输出的路径可能含有环,因此DLX算法必须在递归的过程中实时进行去环操作,简单的说就是一旦发现成环立刻判为不合法解返回。

由于DLX算法会挑图中最薄弱的环节先进行搜索,因此搜索效率高,容易出可行解,搜索的每一步中还可以用Tarjan强连通缩点+Topo排序算法判断当前解是否一定是非法解进行剪枝。

(2)       使用迭代优化算法对初始解进行优化。因为初始解不保证解的优劣性,只保证可行性,因此可以将初始解按关键点分割成一段段“线路”,第一步优化是使用Dijkstra将每对相邻关键点之间的线路进行“绷紧”,用最短路替换DLX搜出来的弯弯曲曲的路径,并且通过增加重边权值有意回避另一条路径上的重边;第二步优化是交换关键点在路径上的出现次序,并且使用“绷紧”算法重新构造可行解,让解的总权值一步步变小。

总体来说,上述算法的问题在于DLX算法在深搜时仍不够强劲,大数据下可能会跑不出解;优化还不够彻底,比不上那些用线性规划算法跑出来的解优。但无论如何,至少这是一系列成功尝试,在写算法的过程中颇具收获。搭整个比赛算法框架的过程中,由于代码量大、细节多,因此对编程风格、DEBUG能力也是非常考验的。在快提交截止的时候发现最短路算法写挂了玩命DEBUG,是一种多么酸爽的体验……

 

以上只是简单地记录了一下算法的思路,算法可以参考:

[1] A*算法:http://baike.baidu.com/view/7850.htm

[2] DLX(Dancing Links AlgorithmX算法):http://www.cnblogs.com/grenet/p/3145800.html

其他图论算法可以参考图论相关书籍。

posted on 2016-05-14 22:55  Indiebard  阅读(803)  评论(0编辑  收藏  举报

导航