2019年吉林大学数学建模校内选拔赛B题的一种思路

笔记 专栏收录该内容
3 篇文章 0 订阅

前几天举办的数学建模校内选拔赛B题是这样的:

B题 中国像素地图城市间最短路优化问题


下图是在http://pixelmap.amcharts.com/ 上生成的中国像素地图. 每个小正方形边长为6px,小正方形之间没有间距(即间距为0px).
在这里插入图片描述

图1


  • 问题1. 根据附件中的文件(amcharts.pixelMap_0.png或amcharts.pixelMap_1.png), 试计算上面中国像素地图中共有多少个这样的小正方形? 要求写出这样的矩阵A, 元素为0或1. 如果小方块在国境内, 即用1代表,
    否则用0表示. 并且要求矩阵A中没有列向量为零向量.
  • 问题2. 注意图2中香港地区的小方块. 试写出它们的像素坐标. 这个坐标是指上题中矩阵A中的坐标, 左上角坐标为(1,1).
  • 问题3. 现在有四个地点 A, B, C, D. 见图2中四个黑色小方块. 彼此之间运输货物, 但是运输途中不能经过吉林、天津、山东、陕西、青海、江西、广西这七个省份/直辖市/自治区(下图中红色区域).
    试绘出A,B,C,D彼此之间的最短路线, 且分别求出经过多少个小正方形?
    在这里插入图片描述

图2


Remark:

  • 这里的所谓最短路线不考虑实际地表的复杂情况(公路、铁路、河流、桥梁、地球曲率等等),仅以附件中所给的平面像素图为准.
  • 附件中的amcharts.pixelMap_0.png和amcharts.pixelMap_1.png本质上同一张图, 只不过后者将若干省份标志了不同颜色.
  • 问题1的求解可以使用amcharts.pixelMap_0.png也可以使用amcharts.pixelMap_1.png.

附件:
amcharts.pixelMap_0.png (图1)
amcharts.pixelMap_1.png (和图2类似,不过没有A、B、C、D四个点)
amcharts.pixelMap_ABCD.png (图2)


毕竟是数学建模的校内选拔赛,没有太难为同学们,难度整体上来说是比较小的。这题的整个程序设计过程,如果交给经常刷OJ或者经常打算法比赛的同学,可能只需要一到两个小时就能全部完成了。

前两问没什么好说的,感觉是来凑问题数的。。。

第一问,用matlab读入图片之后,因为每个小正方形边长为6px,直接水平方向和竖直方向都每隔6个点读取一次颜色的数值,从而把每个6×6的小方格都变成一个像素点,最后整个图会变成一个215×158的矩阵,或者说是一张215×158的图片。在提取颜色之前注意一个小坑——所给图中有的6×6的小方格并不完整,有的只有6×4或者6×3大小,需要在程序里特判并补全,比如下面这个图的最上面一个小方格。

第二问,不用多说了。。。第一问做完了坐标就有了,这个第二问也算是结合了最近的时事热点事件,做数学建模比赛也不能忘记维护国家主权。

第三问,要求四个点两两之间的最短路径以及经过的方格数。
接触过图论的都知道,最短路是图论里面的一个基本问题,有很多种常用的算法,比如SPFA算法、Dijkstra算法、A*算法等等,最暴力的当然是BFS了。看到题目一开始感觉很奇怪,不知道为什么数学建模会出有现成算法的题,感觉不是很合适。后来才发现原来不是考算法,还是在考模型的建立与求解。因为如果模型建得不好,用这些算法求出来的也不是真正的最短路。

什么意思呢?

很多人看到这题第一反应可能会是在一个215×158的网格里找最短路,然后规定只能走上下左右四个方向或者上下左右以及45°对角线方向一共八个方向(简称八方向模型),如下图所示。

然后的话,上下左右走的距离算 1 1 1,对角线走的距离算 2 \sqrt 2 2 ,用代码表示就是

dx=[1,0,-1,0,1,1,-1,-1];
dy=[0,1,0,-1,1,-1,1,-1];
dd=[1,1,1,1,1.414,1.414,1.414,1.414];

那么如果按照这个思路来的话,直接套现成的最短路算法就可以了。有的同学觉得用SPFA算法、Dijkstra算法太丢脸,写的A*算法没写对又调不出来。。。其实,对于这题的数据规模(215×158的网格)来说,写什么算法都能跑出最短路,用时可以忽略不计。笔者试过直接写了一个BFS,剪枝稍微好好写一写的话在matlab里面跑一遍也就不到0.4秒。matlab跑非矩阵运算的算法程序算是比较慢的了,可能是时间常数太大了,换成其他语言的话跑一遍可能也就0.1秒的样子吧。

咱们学微电子的,工科嘛,能用就行,抛开数据规模谈算法没什么太大的实际价值。

下面的图是八方向模型跑出来的最短路,只显示了其中三条,防止交叠看不清路线。
在这里插入图片描述

看起来好像没什么问题?把局部图放大来和真正的最短路径比较一下吧。灰白色的是八方向模型跑出来的最短路,蓝白色的是真正的最短路径。
在这里插入图片描述
在这里插入图片描述
很明显,八方向模型太粗糙了!

如果在LOL或者DOTA之类的游戏里,当你用鼠标想操作一个英雄走到指定位置(英雄会自动绕开墙、防御塔之类的障碍物以最短路径到达指定位置),而这个英雄只会走八方向的话,估计看上去应该会有点智障吧,游戏体验会比较差一点。。。因为真正的最短路径很多时候是一个任意的角度,而不是刚好45°。当然,现在这类游戏的地图模型已经不仅仅是网格模型了,也有的是多边形模型,至于多边形的最短路算法就不再赘述了,网上有很多。

问题在哪里呢?八方向模型是以小方格为不可分割的最小单位,而真正的最短路很多时候是经过小方格的边和格点的。那么改进的思路就很明确了,第一步得重新建图,把方格和格点互易,如下图所示。
在这里插入图片描述在这里插入图片描述

第二步得考虑最短路径的性质。

把题中的国外区域和红色区域统称为非法区域,记为 N N N,其他区域都是可以经过的,称作合法区域,记为 Y Y Y,并规定 N N N Y Y Y都是闭集(即包括区域的外沿线)。那么合法区域和非法区域相接触的边缘线上的点的集合就可以记作 K = N ∩ Y K=N∩Y K=NY

如果把路径看作是一条连接起点和终点的绳子的话,那么当绳子收紧到绷紧时,该路径就是最短路径。既然绳子绷紧了,那么绳子上所有的拐点处必然受到外力,也就是说拐点处必然与格点相接触。

这样一想,问题其实就很简单了。把最短路径看作是分段的折线段,除起点A和终点B外每一段线段的两个端点都必须是集合 K K K内的点,并且每一段线段都不能经过非法区域内(但可以在外沿线上)。
记最短路径为边集 E E E,再翻译成符号语言就是:

E = [ ( A , S 1 ) , ( S 1 , S 2 ) , … , ( S n , B ) ] , ∀ S i ∈ K E = \left[ {(A,{S_1}),({S_1},{S_2}), \ldots ,({S_n},B)} \right],\forall S_i \in K E=[(A,S1),(S1,S2),,(Sn,B)],SiK 且 对 ∀ l i ∈ E , 都 有 l i ∩ C N K = ∅ 且对\forall {l_i} \in E,都有 l_i ∩ {C_N}K=\emptyset liE,liCNK=

那么就只剩下一个问题了,怎么判断两点连线有没有经过非法区域?
熟悉计算几何的可以直接用Cohen-Sutherland算法之类的做,不熟悉的也可以直接分三种情况判断——水平线、竖直线和斜线,也只是多写几个if的事情。

所以整个算法的过程就很清晰了(以BFS算法为例):
第一步求出所有在合法区域和非法区域相接触的边缘线上的点的集合 K K K,把起点A和终点B添加进集合 K K K中,预处理集合 K K K中任意两点连线是否经过非法区域并存下来。(只要第一步预处理完成了其实就把图论模型建完了,也可以用其他更快的算法跑了。)
第二步开一个数组dis(i,j)记录点(i,j)到起点A的当前最短距离,除A点初始化为0外其他点均初始化为INF。然后从起点A出发,遍历集合 K K K中所有能与A点连线不经过非法区域的点(i,j),并与数组dis(i,j)比较,若更短则更新数组dis(i,j)同时把点(i,j)作为第1批入队的点,同时开个数组把点(i,j)的前驱A点存储下来。
第三步重复执行操作,从第k批入队的点(m,n)依次出发,遍历集合 K K K中所有能与点(m,n)连线不经过非法区域的点(i,j),并把dis(m,n)+sqrt((m-i)²+(n-j)²)与数组dis(i,j)比较,若更短则更新数组dis(i,j)同时把点(i,j)作为第k+1批入队的点,同时把点(i,j)的前驱(m,n)存储下来。
第四步当没有新点入队后算法执行结束,从B点一直迭代求前驱点回到A点就是最短路径。

至于最短路径经过了多少个小方格,直接分段求就行了。不过这里有一个隐藏的小彩蛋可以帮助更快地求到结果:

对于一个长度为 m m m,宽度为 n n n的矩形,均分成 m ∗ n m*n mn个小方格,则对角线经过的小方格数量为 m + n − ( m , n ) m+n-(m,n) m+n(m,n),其中 ( m , n ) (m,n) (m,n) m m m n n n的最大公约数。

上述结论的原理请参见笔者的另一篇博文:矩阵的对角线经过的小方格数量https://blog.csdn.net/qq_30205523/article/details/100528069


  • 7
    点赞
  • 2
    评论
  • 5
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值