2017年中兴算法大赛 迪杰特斯拉派
2017-06-23 15:52
471 查看
总结:本人2017年参加的比赛,对于初次参加算法大赛的作者来说,异常激动又有点小窃喜,最后在赛区拿到24名的名次,名次不算高,但是对于一步步解决问题过来的我,经验与经历更为重要,再次做一个小小的总结,也对后续算法提出自己的改进意见,希望对后面参加比赛的你们有一点点启发。
1. 试题介绍
## 赛题 ##最强大脑中的收官蜂巢迷宫变态级挑战,相信大家都叹为观止!最强大脑收官战打响后,收视率节节攀升,就连蚁后也不时出题难为一下她的子民们。在动物世界中,称得上活地图的,除了蜜蜂,蚂蚁当仁不让。在复杂多变的蚁巢中, 蚂蚁总是能以最快、最高效的方式游历在各个储藏间(存储食物)。今天,她看完最新一期节目,又发布了一项新任务:小蚁同学,我需要玉米库的玉米,再要配点水果,去帮我找来吧。小蚁正准备出发,蚁后又说:哎呀,回来,我还没说完呢,还有若干要求如下:
1.小蚁同学,你需要尽可能以最少的花费拿到食物(附件图中路线上的数值表示每两个储物间的花费);
2.小蚁同学,你最多只能经过9个储藏间拿到食物(包含起止两个节点,多次通过同一节点按重复次数计算);
3.小蚁同学,你必须经过玉米间,水果间(附件图中标绿色节点);
4.别忘了,食蚁兽也在路上活动呢,一旦与食蚁兽相遇,性命危矣!不过小蚁微信群公告已经公布了敌人信息(附件图中标红色路段);
5.最后,千万别忘了,还有两段路是必须经过的,那里有我准备的神秘礼物等着你呢(附件图中标绿色路段)。
这下小蚁犯难了,这和它们平时找食物的集体活动规则不一样嘛,看来这次需要单独行动了。要怎么选路呢?小蚁经过一番苦思冥想,稿纸堆了一摞,啊,终于找到了!亲爱的同学们,你们能否也设计一种通用的路径搜索算法,来应对各种搜索限制条件,找到一条最优路径,顺利完成蚁后布置的任务呢?
注:
1、蚁巢,有若干个储藏间(附件图中圆圈表示),储藏间之间有诸多路可以到达(各储藏间拓扑图见附件);
2、节点本身通行无花费;
3、该图为无向图,可以正反两方向通行,两方向都会计费,并且花费相同;
4、起止节点分别为附件图中S点和E点。
5、最优路径:即满足限制条件的路径。
2. 赛题分析
从赛题中,可以简化归纳一下题目的几个要求,首先从S点出发,终点是E,图中寻找最优路径,其中N2-N4,N13-N14为必走线段,N7,N12为不可走的点,N12-N11为不可走的线段,要求在九个点之内,到达终点,起点终点,计算在内,九点走不完,求次优路径。
3. 赛题解析
限制节点算法分析
限制算法关键点提示:
1.必经线段处理:在经过线段一个端点以后,下一步直接经过另一个端点,而不会经由其他节点再绕回另一端点,迪杰斯特拉是通过计算比较最短步长确定下一个节点的,那么,在遇到必经线段的一个端点时,则跳过计算步长比较,直接将另一个端点定为下一个经过节点即可。
2.不可经过线段处理:因为图的存储是利用HashMa来存储节点以及节点之间的步长信息的,因为可以直接在查询操作前,将不可经过节点之间的步长直接删除,简化操作。
3.必经节点处理:令0为起点,分别求出起点到每个必经节点的步长,找到步长最短的必经节点为第一个经过的必经节点(已达节点就可以不用计算了),然后以此为起点,重复上述操作,直到所有必经节点都经过以后,最后到达17终点。
4. 代码分析
对于迪杰斯特拉算法,网上有很多介绍,也有现成的代码,大同小异,本人在拿到赛题以后,也是查阅了很多资料,最终采用了这位博客的代码作为基础来进行后续的延伸,http://blog.csdn.net/xiaojimanman/article/details/50889670,他写的非常的有条理而又清晰,代码完全可以运行,所以我也是非常感谢这位前辈。
拿下迪杰特斯拉基础算法以后,我们可以把赛题的题按照代码的输入的格式进行修改,比较无聊,图很大就麻烦了,很多人采用了矩阵,利用写好的规范图数据,通过代码读取配置文件来加载图,感觉这样更方便,可以采用。
4.1 限制点路径排序
题目要求必经线段可转化为必经点N2与N4, N12与N11,但是只要出现,必成对出现,如果排到N2,则后面强制排序N4,以此类推。
将必须经过的线段先转化为节点,因此题目转化为必须经过7,12,2,4,13,14,用一个s数组存放,其中0为起点,17位终点。
从start=s[i])开始,end=s[j],(i=0,j=i+1)分别算出是s[i]到s[j]的距离L,将距离起点最近的点与s[i+1]交换位置,然后令start=s[i+1],end=s[j],如果遇到s[i+1]=必须经过的线段端点(2-4或13-14),则分析下一个点s[i+2]是否是对应的端点,若果是则不需要变化。否则,从i+3开始寻找对应的端点,找到以后,将其与s[i+2]交换位置,然后令start=s[i+2]继续寻找。
4.2 最优路径排序
先定义一个LinkedList用于存放路径:
然后通过迪杰斯特拉算法,分别求出S数组里结两两节点之间最短路径,如果查找到s[i]=必须经过的线段端点(2-4,13-14),则跳过迪杰斯特拉算法求最短路径,直接将后一位节点(上一步限制路径排序,已经将对应线段节点排序好,所以都是成对出现)存入ls集合,最短步长直接利用HashMap的key来求步长value。
上面图为测试代码分析,分别将限制节点两两之间的路径取出放入ls集合保存,若遇到必经线段端点(2-4或13-14),则跳过,后面的重复上一步骤。
5.输入结果测试分析
后期总结
工作已经差不多完成了,后面评分建议是小主的论文有些地方叙述的不够清晰完成,叙述的太少了,说真话,你让我最多写5页,不要写太多,所以我缩缩减减,写了6页,但是最后看人间评语夸人家说有人给出了20几个测试结果,加上代码分析,让我很是惊讶,这得多少页啊,说好的大赛论文格式要求,555,伤心。
这题赛题,是没有最优解的,后期我仔细思考过,在代码问题上是没有问题,但是在次优解的倾向上,我没有做出重点分析,究竟是以路径最优,还是限制点数9以内最优,在最短路径的选择上,需要做出更多的分析,
(1)采用迪杰特斯拉算法,判断下一个最优点时,计算该点到下一可达点的路径最小点为最优点,但是实际操作中,会遇到可达路径最小的点不止一个,那么如何判断,该点分析很重要。
(2)我得出的结果是按路径最优算的,没有照点数最优算,读者可自行思考。
(3)随着图的变大,求最优路径的时间复杂度也在变大,算法的选择,也可以参考更多的优秀算法,最近在看多线程高并发,有了一点思考,在导入图,即第一次加载时,将每一个点的下一个最优可达点做好标记,类似HshaMap,的key,value,保存下来,程序一旦访问到该点,既可以免去重复寻找最优点的时间,大大缩减工程量。
需要源代码的可以在下面留言。。谢谢支持!
1. 试题介绍
## 赛题 ##最强大脑中的收官蜂巢迷宫变态级挑战,相信大家都叹为观止!最强大脑收官战打响后,收视率节节攀升,就连蚁后也不时出题难为一下她的子民们。在动物世界中,称得上活地图的,除了蜜蜂,蚂蚁当仁不让。在复杂多变的蚁巢中, 蚂蚁总是能以最快、最高效的方式游历在各个储藏间(存储食物)。今天,她看完最新一期节目,又发布了一项新任务:小蚁同学,我需要玉米库的玉米,再要配点水果,去帮我找来吧。小蚁正准备出发,蚁后又说:哎呀,回来,我还没说完呢,还有若干要求如下:
1.小蚁同学,你需要尽可能以最少的花费拿到食物(附件图中路线上的数值表示每两个储物间的花费);
2.小蚁同学,你最多只能经过9个储藏间拿到食物(包含起止两个节点,多次通过同一节点按重复次数计算);
3.小蚁同学,你必须经过玉米间,水果间(附件图中标绿色节点);
4.别忘了,食蚁兽也在路上活动呢,一旦与食蚁兽相遇,性命危矣!不过小蚁微信群公告已经公布了敌人信息(附件图中标红色路段);
5.最后,千万别忘了,还有两段路是必须经过的,那里有我准备的神秘礼物等着你呢(附件图中标绿色路段)。
这下小蚁犯难了,这和它们平时找食物的集体活动规则不一样嘛,看来这次需要单独行动了。要怎么选路呢?小蚁经过一番苦思冥想,稿纸堆了一摞,啊,终于找到了!亲爱的同学们,你们能否也设计一种通用的路径搜索算法,来应对各种搜索限制条件,找到一条最优路径,顺利完成蚁后布置的任务呢?
注:
1、蚁巢,有若干个储藏间(附件图中圆圈表示),储藏间之间有诸多路可以到达(各储藏间拓扑图见附件);
2、节点本身通行无花费;
3、该图为无向图,可以正反两方向通行,两方向都会计费,并且花费相同;
4、起止节点分别为附件图中S点和E点。
5、最优路径:即满足限制条件的路径。
2. 赛题分析
从赛题中,可以简化归纳一下题目的几个要求,首先从S点出发,终点是E,图中寻找最优路径,其中N2-N4,N13-N14为必走线段,N7,N12为不可走的点,N12-N11为不可走的线段,要求在九个点之内,到达终点,起点终点,计算在内,九点走不完,求次优路径。
3. 赛题解析
限制节点算法分析
限制算法关键点提示:
1.必经线段处理:在经过线段一个端点以后,下一步直接经过另一个端点,而不会经由其他节点再绕回另一端点,迪杰斯特拉是通过计算比较最短步长确定下一个节点的,那么,在遇到必经线段的一个端点时,则跳过计算步长比较,直接将另一个端点定为下一个经过节点即可。
2.不可经过线段处理:因为图的存储是利用HashMa来存储节点以及节点之间的步长信息的,因为可以直接在查询操作前,将不可经过节点之间的步长直接删除,简化操作。
3.必经节点处理:令0为起点,分别求出起点到每个必经节点的步长,找到步长最短的必经节点为第一个经过的必经节点(已达节点就可以不用计算了),然后以此为起点,重复上述操作,直到所有必经节点都经过以后,最后到达17终点。
4. 代码分析
对于迪杰斯特拉算法,网上有很多介绍,也有现成的代码,大同小异,本人在拿到赛题以后,也是查阅了很多资料,最终采用了这位博客的代码作为基础来进行后续的延伸,http://blog.csdn.net/xiaojimanman/article/details/50889670,他写的非常的有条理而又清晰,代码完全可以运行,所以我也是非常感谢这位前辈。
拿下迪杰特斯拉基础算法以后,我们可以把赛题的题按照代码的输入的格式进行修改,比较无聊,图很大就麻烦了,很多人采用了矩阵,利用写好的规范图数据,通过代码读取配置文件来加载图,感觉这样更方便,可以采用。
4.1 限制点路径排序
题目要求必经线段可转化为必经点N2与N4, N12与N11,但是只要出现,必成对出现,如果排到N2,则后面强制排序N4,以此类推。
private static void RestrictedRouting(HashMap<Integer, HashMap<Integer, Integer>> stepLength, int[] s, int[] limit) { // 限制点的路径排序 int Temp; int min; int tempStep; int index; // 依次为临时变量,最短步长,临时步长,索引 distance dis = new DistanceDijkstraImpl(); for (int i = 0, len = s.length - 1; i < len; i++) { index = i; // index指向当前 min = dis.getMinStep(s[i], s[i + 1], stepLength).getMinStep(); for (int j = i + 1; j < len; j++) { tempStep = dis.getMinStep(s[i], s[j], stepLength).getMinStep(); System.out.print(tempStep + ","); // 测试:依次输出最短路径 if (min > tempStep) { min = tempStep; index = j; continue; // 找到步长最短的那个索引赋值给later } } System.out.print("index="+index+" ,i="+i); System.out.println(); //测试:输出当前起始点i,最短路径的索引值 if (index - i > 1) { Temp = s[index]; s[index] = s[i + 1]; s[i + 1] = Temp; // 如果最短步长索引刚好就是后一位,则不需要换位置,否则调换位置 } if (s[i] == limit[3] || s[i] == limit[4] || s[i] == limit[5] || s[i] == limit[6]) { forceSort(s, i, limit); // 每次排序完就找当前索引指向的值是否是线段的某一个端点,如果是,执行方法forceSort, // 从当前端点往后找到线段对应的另一个端点,放在后一位。比如先找到2.则找到4放在后一位。 } for (int a : s) { System.out.print(a + ","); } System.out.println(); // 测试:输出需要经过的点临时排序 } }
private static final void forceSort(int[] s, int i, int[] limit) { // 强制排序 int temp; if ((s[i] == limit[3] || s[i] == limit[4])) { for (int k = i + 2; k < s.length; k++) { // 如果定位到线段的某一个端点A,则从A索引值往后找到另一个端点B // 的索引值,将端点A后一位换成B if (s[k] == limit[3]) { i++; temp = s[k]; s[k] = s[i]; s[i] = temp; i--; break; } if (s[k] == limit[4]) { i++; temp = s[k]; s[k] = s[i]; s[i] = temp; i--; break; } } } if ((s[i] == limit[5] || s[i] == limit[6])) { for (int k = i + 2; k < s.length; k++) { // 类似,对应端点可假设为C if (s[k] == limit[6]) { i++; temp = s[k]; s[k] = s[i]; s[i] = temp; i--; break; } if (s[k] == limit[5]) { i++; temp = s[k]; s[k] = s[i]; s[i] = temp; i--; break; } } } }
将必须经过的线段先转化为节点,因此题目转化为必须经过7,12,2,4,13,14,用一个s数组存放,其中0为起点,17位终点。
从start=s[i])开始,end=s[j],(i=0,j=i+1)分别算出是s[i]到s[j]的距离L,将距离起点最近的点与s[i+1]交换位置,然后令start=s[i+1],end=s[j],如果遇到s[i+1]=必须经过的线段端点(2-4或13-14),则分析下一个点s[i+2]是否是对应的端点,若果是则不需要变化。否则,从i+3开始寻找对应的端点,找到以后,将其与s[i+2]交换位置,然后令start=s[i+2]继续寻找。
4.2 最优路径排序
先定义一个LinkedList用于存放路径:
然后通过迪杰斯特拉算法,分别求出S数组里结两两节点之间最短路径,如果查找到s[i]=必须经过的线段端点(2-4,13-14),则跳过迪杰斯特拉算法求最短路径,直接将后一位节点(上一步限制路径排序,已经将对应线段节点排序好,所以都是成对出现)存入ls集合,最短步长直接利用HashMap的key来求步长value。
private static void OptimalPathJudgment(HashMap<Integer, HashMap<Integer, Integer>> stepLength, int[] s, int[] limit) { LinkedList<Integer> ls = new LinkedList<Integer>(); // 将路径存入ls distance dis = new DistanceDijkstraImpl(); MinStep step; //最短路径 int stepSize = 0; //步长 ls.add(s[0]); // 把起点放入S数组 for (int i = 0, len = s.length - 1; i < len; i++) { if ((s[i] == limit[3] || s[i] == limit[4] || s[i] == limit[5] || s[i] == limit[6])) { stepSize += stepLength.get(s[i]).get(s[i + 1]); ls.add(s[++i]); } step = dis.getMinStep(s[i], s[i + 1], stepLength); //得到相邻两节点最短路径 stepSize += step.getMinStep(); //起点到可达节点步长总和 step.getStep().remove(0); //将路径第一个节点删除 ls.addAll(step.getStep()); //将最短路径全部放入ls集合中 System.out.println("step: " + step.getStep() + " ,countNum: " + ls.size() + ls + stepSize);//测试 :输出求取的相邻两点之间的路径,步长 } if (ls.size() <= 9) { System.out.println("恭喜你,在条件限制下,能够得到最优路径!在经过" + ls.size() + "点以后达到终点" + ",最优路径为" + ls + ",最短步长为" + stepSize); } if (ls.size() > 9) { System.out.println("对不起,在条件限制下,无法得到最优路径!为了达到目的可以在经过" + ls.size() + "点以后达到终点,次优路径为" + ls + "\n"+",最短步长为" + stepSize+"!你需要修改限制条件重新查找!"); } }
上面图为测试代码分析,分别将限制节点两两之间的路径取出放入ls集合保存,若遇到必经线段端点(2-4或13-14),则跳过,后面的重复上一步骤。
5.输入结果测试分析
后期总结
工作已经差不多完成了,后面评分建议是小主的论文有些地方叙述的不够清晰完成,叙述的太少了,说真话,你让我最多写5页,不要写太多,所以我缩缩减减,写了6页,但是最后看人间评语夸人家说有人给出了20几个测试结果,加上代码分析,让我很是惊讶,这得多少页啊,说好的大赛论文格式要求,555,伤心。
这题赛题,是没有最优解的,后期我仔细思考过,在代码问题上是没有问题,但是在次优解的倾向上,我没有做出重点分析,究竟是以路径最优,还是限制点数9以内最优,在最短路径的选择上,需要做出更多的分析,
(1)采用迪杰特斯拉算法,判断下一个最优点时,计算该点到下一可达点的路径最小点为最优点,但是实际操作中,会遇到可达路径最小的点不止一个,那么如何判断,该点分析很重要。
(2)我得出的结果是按路径最优算的,没有照点数最优算,读者可自行思考。
(3)随着图的变大,求最优路径的时间复杂度也在变大,算法的选择,也可以参考更多的优秀算法,最近在看多线程高并发,有了一点思考,在导入图,即第一次加载时,将每一个点的下一个最优可达点做好标记,类似HshaMap,的key,value,保存下来,程序一旦访问到该点,既可以免去重复寻找最优点的时间,大大缩减工程量。
需要源代码的可以在下面留言。。谢谢支持!
相关文章推荐
- 第一届中兴捧月算法大赛迪杰斯特拉派解决方案
- 2017年中兴捧月神算师算法精英挑战赛之阿尔法勒克斯特派(AlphaNext派)-----进来加群咯
- 2017年浙江工业大学大学生程序设计迎新赛决赛—网络同步赛 D-序列【莫队算法】
- 通过剪枝来避免不必要循环的dfs算法实例,2017年计蒜课模拟赛(五)第六题
- “第一届腾讯高校算法大赛”初赛失败总结
- 2月28日云栖精选夜读:用人工智能提升营销效率,阿里妈妈启动2018国际广告算法大赛
- [置顶] 阿里2017年-图形图像算法工程师-在线编程题目
- CaoHaha's staff(中国大学生程序选拔赛2017年网络大赛)
- 2017年浙江工业大学大学生程序设计迎新赛决赛—网络同步赛 D-序列【莫队算法】
- 乐师2017年新生程序设计大赛解题报告
- 滴滴算法大赛算法解决过程 - 拟合算法
- 关于TopCoder算法设计大赛宣讲会
- 天翼杯大数据算法应用大赛感想
- 搜狐图文匹配算法大赛_方案分享
- 2017年网易校招算法编程题:数论 (PHP版)
- 京东JData算法大赛——高潜用户购买意向预测
- 山东农业大学算法大赛举办圆满成功
- 最后一公里极速配送 - 阿里云算法大赛总结
- 湖南大学ACM程序设计新生杯大赛 - E Permutation (匈牙利算法)
- 最短路径迪杰特斯拉算法