总结:本人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,以此类推。

    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后一位换成Bif (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++) { // 类似,对应端点可假设为Cif (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>(); // 将路径存入lsdistance 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年中兴算法大赛 迪杰特斯拉派相关推荐

  1. 第一届中兴捧月算法大赛迪杰斯特拉派解决方案

    迪杰斯特拉派初赛赛题 最强大脑中的收官蜂巢迷宫变态级挑战,相信大家都叹为观止!最强大脑收官战打响后,收视率节节攀升,就连蚁后也不时出题难为一下她的子民们.在动物世界中,称得上活地图的,除了蜜蜂,蚂蚁当 ...

  2. 2020中兴捧月算法精英挑战赛-迪杰斯特拉派初赛(未来城市物流系统)总结

    疫情关系,导致科研一直没法开展,老板着急,自己也无所事事.在清明过后看到了中兴的算法精英挑战赛,然后就开始了算法之旅,这里自己做一点总结,为自己以后争取点教训吧. 数据分析的重要性 这次比赛真的让我体 ...

  3. 优先队列实现迪杰特斯拉模板

      迪杰特斯拉还是比较常用的最短路径算法.之前学数据结构时写的代码很冗余,总是记不住.今天有时间,整理出一个简练的模板吧!   实现的方式对应了优先队列,模板中包括建图的方法(其实哪种都可以).本文用 ...

  4. [转]最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现

    最短路径算法-Dijkstra(迪杰斯特拉)算法分析与实现(C/C++) Dijkstra算法 ----------- 最后更新时间:2011.9.25 ----------- Dijkstra(迪杰 ...

  5. 0096 克鲁斯卡尔算法,迪杰斯特拉算法

    /*  * 克鲁斯卡尔算法  * 1.用来求加权连通图的最小生成树的算法  * 2.思想:按照权值从小到大的顺序,选择n-1条边,并保证这n-1条边不构成回路  * 3.先构造一个只含n个顶点的森林, ...

  6. 图 相关算法~从头学算法【广搜、 深搜、 拓扑排序、 并查集、 弗洛伊德算法、迪杰斯特拉算法】

    图的相关主流算法主要有: 广度优先搜索 深度优先搜索 拓扑排序 并查集 多源最短路径(弗洛伊德算法) 单源最短路径(迪杰斯特拉算法) 其中呢,最基本的是前两种,也就是平时常用的广搜和深搜,本文中将概要 ...

  7. 数据结构第十二天——普利姆算法和迪杰斯特拉算法

    普利姆(Prim)算法求最小生成树,也就是在包含 n个顶点的连通图中,找出只有(n-1)条边包含所有 n个顶点的连通子图,也就是所谓的极小连通子图 最小生成树:给定一个带权的无向连通图,如何选取一棵生 ...

  8. 算法学习--迪杰斯特拉和弗洛伊德

    一.迪杰斯特拉 求解图中由起点开始到其他节点的最短路径问题(权值不能为负). 主要思想:在有权值的图中,直接和起点相连的节点他们的最短路径为和起点相连的边的权值,和起点没有直接相连的节点默认为该点和起 ...

  9. 最短路径 [迪杰特斯拉算法] ---图

    在网图和非网图中,最短路径的含义是不同的.      -网图是两定点经过的边打上权值之和最少的路径.      -非网图是两顶点之间经过的边数最少的路径. 我们把路径起始的第一个顶点称为源点,最后一个 ...

最新文章

  1. 一生受益的三个小故事
  2. linux 系统调用 open函数使用
  3. 论文: Data-Driven Evolutionary Optimization: An Overview and Case Studies(2):五个实例分析
  4. 网络专业人士笔记(1~4章)
  5. [转载]C#时间函数
  6. android 半圆滚动菜单,自定义控件:实现半圆滚动菜单效果
  7. Palindrome DP
  8. centos7 host修改
  9. mysql安装设置数据目录下_Windows下修改MySQL安装目录和MySQL数据目录
  10. [已解决]linux ubuntu unicode emoji字符显示问题
  11. 通达oa 2013 php解密,通达OA 2011-2013 通杀GETSHELL修复补丁
  12. PS如何做文字扫描效果
  13. 联通loid认证_光纤LOID 认证 需要填写的用户名是什么?有人说不需要填写密码。为什么我每次认证都是超时?...
  14. Mac上将多张图片转化为pdf文档并添加水印
  15. 基于F28335指纹识别系统
  16. RealWin Server HMI 漏洞复现与恶意攻击链分析
  17. gdc矫正_GDC 2015的众多游戏
  18. C语言经典一百题(六)用*号输出字母C的图案。
  19. 如何在Commander One中显示隐藏文件?
  20. Eclipse 注释乱码

热门文章

  1. 微信小程序实现评论多级展开收起以及点赞功能
  2. Kruskal算法求最小生成树
  3. 【APICloud系列|1】华为应用市场 应用版权证书或代理证书怎么填
  4. python matplotlib contour画等高线图
  5. Matplotlib 中等高线图(contour)的绘制
  6. JAVA实现逆波兰转换,java实现逆波兰式
  7. Tracup:集成Bug追踪的轻量级项目管理平台
  8. 【Cesium】智慧城市建筑白模泛光特效
  9. cesium实现立体墙(垂直、水平)渐变泛光效果
  10. 块存储,文件存储,对象存储