![]() |
分治、递归、分类和最小距离。
分治、递归、分类和最小距离。
www.dimcax.com 分治、递归、分类和最小距离。 给定平面上的一个数量为n的点集,如何能有效地找出距离最近的点对呢?(在实际中有着应用,而且给出的是点对的集合,也就是在误差范围内的所有点对都找出来)。 这个问题很容易理解,似乎也不难解决。我们只要将每一点与其他n-1个点的距离算出,找出达到最小距离的两个点即可。然而,这样做效率太低,需要o(n^2)的计算时间。当数量规模较小时,尚能解决,但一旦规模达到万级以上,其速度之慢,时间之长,无法令人忍受。下面我给出这个问题的一个θ(nlogn)算法。 在这个算法中,我利用了递归、分治和分类思想。 递归算法是自身调用自身函数的一种算法,例如求阶乘: (defun jc(n) (if (= n 0) 1 (* n (jc (1- n))))) 分治算法是对于一个规模为n的问题,把它分解成为k个规模较小的子问题,这些子问题互相独立,且结构与原来问题的结构相同。在解这些子问题时,又对于每一个子问题进行进一步的分解,直到某个阈值为止。递归地解决这些子问题,再把各个子问题的解合并起来,就得到原来问题的解。因此递归一般和分治联系在一起。 对于求最小距离的解,我参考了一些资料,他们给出的大多是c++ 程序,我看不懂,只好按照算法和思想来设计lisp程序。 闲话少说,先看源程序:加载程序,运行te 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 ;;定义错误函数和预处理 ( "errno" 0) ( olderr *error*) ( *error* (msg) ( en ( "errno")) ( errmsg ( "errno=" ( en) "\nerror:" msg)) ( errmsg) ( *error* olderr) ) () ( oldmode ( "osmode")) ( oce ( "cmdecho")) ( "cmdecho" 0) ( ".ucs" "w") ;;也可以用其他方式取得点集 ( sl '((0 . "point"))) ( t0 ( "tdusrtimer")) ( ss ( sl)) ( ptlist (getpt ss)) ;;分类 ( t0 ( "tdusrtimer")) ( ptlist (sortx ptlist)) ( "\n函数排序用时") ( ( (- ( "tdusrtimer") t0) 86400)) ( "秒") ;;函数用时估算,以了解函数性能 ( t0 ( "tdusrtimer")) ( pp1 (f2 ptlist) pp ( pp1)) ( "\n函数查找用时") ( ( (- ( "tdusrtimer") t0) 86400)) ( "秒") ( ( nil pp) ( ( "不存在有最小距离的一对点!") ( ".ucs" "p") ( "osmode" oldmode) ( "cmdecho" oce) () ) ( ;;画最短距离的点对集的连线,可能有多条 ( "osmode" 0) ( nn pp ( ( '((0 . "line")(100 . "acdbentity")(100 . "acdbline")) ( ( 10 ( nn))) ( ( 11 ( nn))) ( ( 62 1)) ) ) ) ( ".ucs" "p") ( "osmode" oldmode) ( "cmdecho" oce) () ) ) ) ;;取点函数,其中i为点的编号 ( getpt (ss / i listpp a b c) ( i 0 listpp nil ) ( ss ( ( ss) ( a ( ss i)) ( b ( a)) ( c ( ( 10 b))) ( listpp ( c listpp)) ( i ( i)) ) ) ( listpp) ) ;;从j到k的表 ( cut (ptlist j k / i ptlist1) ( i 0 ptlist1 nil) ( n ptlist ( ( ( i j) ( i k) ) ( ptlist1 ( n ptlist1)) ) ( i ( i)) ) ( ptlist1) ) ;;对x排序 ( sortx (ptlist) ( '( (x) ( x ptlist)) ( ptlist '( (e1 e2) ( ( e1)( e2)))) ) ) ;;在带形区域查找 ( searchx (ptlist1 x1 x2 / pp) ( pp nil) ( n ptlist1 ( ( ( ( n) x1) ( ( n) x2) ) ( pp ( n pp)) ) ) ( pp) ) ;;在矩形区域查找 ( searchxy (ptlist2 x1 x2 y1 y2 / pp) ( pp nil) ( n ptlist2 ( ( ( ( n) x1) ( ( n) x2) ( ( n) y1) ( ( n) y2) ) ( pp ( n pp)) ) ) ( pp) ) ;;最多6点最小距离 ( 6ptmin (ptlist4 pt / 6pmin 6plist) ( 6pmin ( '( (x) ( x pt)) ptlist4)) ( 6pmin ( 'min 6pmin) 6plist nil) ( 6name ptlist4 ( ( ( 6name pt) 6pmin 1e-8) ( 6plist ( ( pt 6name) 6plist)) ) ) ( ( 6pmin 1e-8) 6plist) ) ;;*************** ;;程序主段------- ( f2 (ptlist / l p1 p2 p3 dd 3pmind 3plist ptlist1 ptlist2 ptlist3 ptlist4 n m midpt mind1 mind2 mindt a b c d dismin dnmin nplist mindi) ( l ( ptlist)) ( ( ( l 2);;两点还用说 ( ( ( ( ptlist) ( ptlist)) 1e-8) ( ptlist) ) ;;( ( 'distance ptlist) ( ptlist)) ) ( ( l 3);;三点最小距离直接求解点对 ( ( p1 ( ptlist) p2 ( ptlist) p3 ( ptlist)) ( dd ( ( ( p1 p2) ( p1 p2)) ( ( p1 p3) ( p1 p3)) ( ( p2 p3) ( p2 p3)) ) ) ( 3pmind ( 'min ( 'car dd))) ( 3plist nil) ( 3name dd ( ( ( 3name) 3pmind 1e-8) ( 3plist ( ( 3name) 3plist)) ) ) ( ( 3pmind 1e-8) 3plist) ) ) ( ( l 3) ( ( n ( l 2) m (- l n));;分治 ( ptlist1 (cut ptlist 0 (1- m))) ( ptlist2 (cut ptlist m l)) ( midpt ( ptlist1)) ( mind1 (f2 ptlist1));;递归左边 ( mind2 (f2 ptlist2));;递归右边 ( mindt ( (( ( mind1) ( mind2) 1e-8)( ( mind1) ( ( mind1) ( mind2)))) (( ( mind1) ( mind2)) mind1) ( mind2) ) ) ( mindi ( mindt)) ( a (- ( midpt) mindi) b ( midpt)) ( ptlist3 (searchx ptlist1 a b)) ( ( ptlist3 nil) ( ( dismin nil) ( name ptlist3 ( a ( midpt) b ( ( midpt) mindi) c (- ( name) mindi) d ( ( name) mindi)) ( ptlist4 (searchxy ptlist2 a b c d)) ( ( ptlist4 nil) ( dismin ( (6ptmin ptlist4 name) dismin)) ) ) ( ( dismin nil) mindt ( ( dnmin ( 'min ( 'car dismin)) nplist nil) ( npname dismin ( ( ( npname) dnmin 1e-8) ( nplist ( ( npname) nplist)) ) ) ( (( ( mindt) dnmin 1e-8) ( mindi ( nplist ( mindt)))) (( ( mindt) dnmin) mindt) ( ( dnmin nplist)) );;for inest cond );;for inest if-progn );;for inest if )mindt;;for if-progn );;for if );;for cond-last-progn );;for cond-last );;for cond );;for defun ;;*************** 比较了一些别人写的代码,(大都是平方级别的,有的甚至更高),发现在时间上还是比平方级以上的要快很多。但是还没有做最优处理,希望大家多多提意见给我。 通过工具菜单->加载应用程序 可加载该程序,然后可直接在命令行输入相关命令运行。如需要每次启动时均加载该程序,则可以将该文件放在启动组中。 文件预览: 以下图片给出了一个极端例子: /blog/user1/90/index.asp 好帖!顶到底。 lisp vba arx .net开发都会一点。可惜都不精。希望和大家共同学习进步。 www.zsqsoft.com d 算法对程序来说至关重要,还请楼主给大伙讲一讲数据结构和算法。 lisp vba arx .net开发都会一点。可惜都不精。希望和大家共同学习进步。 www.zsqsoft.com d 这个题的算法步骤如下: 1、首先把点集按照x从小到大分类, 2、先求两点和三点的最小距离点对。 3、对于大于三点以上的n个点,做如下考虑: a,把点按照中位数分开。(例如,19个点,则左边10个,右边9个,18个对分) b,对两边分别用递归方法求解。 得到两个最小的距离d1和d2 c ,比较d1或者d2大小,取最小的为dmin d ,设置中位点x坐标为xmid ,对于落在 (xmid-dmin,xmid) 区域上的点(xscan, yscan) 进行扫描x落在(dmin,xmid+dmin)y落在( yscan-dmin,yscan+xdmin) 右边的点(理论证明最多有6个这样的点),分别求左边扫描的点跟右边区域的点的距离,找到距离的最小,然后从最小的合集中找到最小 midarea-min,把这个值跟dmin做比较,这样就可以得出最小的距离以及它们的点对。 如果不明白的话,可以参考一些书籍和网上的资料。 /blog/user1/90/index.asp 学习ing d 感谢版主分享,谢谢 |
| 所有的时间均为北京时间。 现在的时间是 05:54 PM. |