老王论坛

标题: RPG游戏的寻路算法——从绯月讲起 [打印本页]

作者: Applcu    时间: 2023-12-25 18:31
标题: RPG游戏的寻路算法——从绯月讲起
本帖最后由 navebayes 于 2023-12-26 12:02 编辑
1 D4 w7 \2 P9 H9 z3 o) b+ U
0 v) r4 l9 X: R/ G; t2 N+ i5 V最近正在玩个游戏,也算是国产之光绯月仙行录,这个游戏哪里都好就是bug太多,并且作者过于摆烂,以至于有很多玩家都认为这个游戏就是故意拖着吃赞助的(bushi)8 K# D* n" m% {6 y% B' i(欢迎访问老王论坛:laowang.vip)
言归正传,在游玩这个游戏的过程中,我在一个评论区里看到这样一段话:自从玩了绯月之后,对于其他RPG游戏都看不上眼了,因为这个游戏独创了自动寻路的功能,可以说是RPG类游戏的里程碑式壮举。
2 A) _+ c7 I% s0 \: p我对此感到好奇,因为从前从来没有游玩RPG类游戏的经验,但我学过一点点算法,于是我打算用一些浅显易懂的方式说说自动寻路这样一个功能的实现。
% J# t, R2 o( p6 ^; e- `* e% ^# M% Q! B7 V3 j2 ~(欢迎访问老王论坛:laowang.vip)
主流的寻路算法:深度优先,广度优先,Dijkstra,A* 等,我这里主要讲讲后两种。
+ T8 I* Z9 O+ j: h  z. [6 I+ @; x: a( j6 {8 a: A8 z(欢迎访问老王论坛:laowang.vip)
Dijkstra算法:这个算法是目前很多地图软件都在使用的算法,采用OPEN,CLOSE表的方式实现寻路功能。
; t4 t3 P- M% [- @) q    创建两个表,OPEN, CLOSE。# s* ?* s8 w$ f/ Z# l/ N. o(欢迎访问老王论坛:laowang.vip)
OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。$ C( u3 o# {0 M) U( u(欢迎访问老王论坛:laowang.vip)
1. 访问路网中里起始点最近且没有被检查过的点,把这个点放入OPEN组中等待检查。% Y: Y# n8 R( A$ n6 U2 m! C(欢迎访问老王论坛:laowang.vip)
2. 从OPEN表中找出距起始点最近的点,找出这个点的所有子节点,把这个点放到CLOSE表中。
. Q" t5 y# K: T! _' x3. 遍历考察这个点的子节点。求出这些子节点距起始点的距离值,放子节点到OPEN表中。
% |* X; v. u3 I/ a7 M3 S4. 重复2,3,步。直到OPEN表为空,或找到目标点。
0 M$ v; B$ R9 H! ^
4 [% r* t" d% ~; n: [* e2 t" g7 N实际写代码还是比较占行数的,直接给出链接如下。
( d2 g+ M# I0 S( w+ k1 I参考:https://blog.csdn.net/YiYeZhiNian/article/details/1222174503 I) T2 t: N% _) D- P1 N(欢迎访问老王论坛:laowang.vip)
' G2 F6 T- C6 y" r5 a(欢迎访问老王论坛:laowang.vip)
用这个算法,我写过一个课程作业,具体就是对于各个城市的地铁最短路径规划,大致还是比较成功的。先说说个人对于Dijkstra算法设计地铁线路规划:/ Z% r1 m+ B7 j5 g! _(欢迎访问老王论坛:laowang.vip)
1.首先用爬虫爬到该城市的地铁网络,包含站点名称,该站点经纬度和线路图,并生成excel表格。用该excel表格生成pickle文件,方便直接调用。- R/ d0 u* l. s. \+ U5 N$ k: v(欢迎访问老王论坛:laowang.vip)
2.注册高德地图开发者账号(该功能需要实名),得到一个key用于调用api(每日上限100次,超过付费,我调试到后面不让我调试了...)
, I4 N) A: ~$ X) ]3.输入始发地和目的地,并通过api返回两个位置的经纬度坐标。7 z( L+ f( q4 M& {(欢迎访问老王论坛:laowang.vip)
4.比较两地理位置之间的最近地铁站,并根据Dijkstra算法实现路径规划。6 r/ r( @7 b$ n8 k2 d  M) X' F3 A7 x(欢迎访问老王论坛:laowang.vip)
5.Dijkstra算法的本质就是不断选择新顶点并更新已处理表,并将他和邻居节点进行比对,当所有节点都被处理后即为最短路径3 Q4 m+ B$ J0 R(欢迎访问老王论坛:laowang.vip)
至此,已初步完成具体工作流程。; g! J8 g+ {1 U) y(欢迎访问老王论坛:laowang.vip)
  1. def get_nearest_subway(data,longitude1,latitude1):
    8 R& B8 I/ Y! J/ m+ v: M0 L. ^
  2.   #找最近的地铁站  I5 U2 V; ]! ?) G2 f  [7 z(欢迎访问老王论坛:laowang.vip)
  3.   longitude1=float(longitude1)
    . U$ q6 U* B: x- h
  4.   latitude1=float(latitude1)
    & F+ e7 Q! N4 O( @0 L8 Z: ?
  5.   distance=float('inf')
    3 d2 {4 Q) r4 D) S# s1 }
  6.   nearest_subway=None
    0 x, e! T4 }$ B! ?0 N  H) X  e  s
  7.   for i in range(data.shape[0]):
    - }; r. R/ R: A' f0 ]% P+ V
  8.     site1=data.iloc[i]['name']    , z7 I6 o' h. t  A% C& G! s% I(欢迎访问老王论坛:laowang.vip)
  9.     longitude=float(data.iloc[i]['longitude'])
    * i4 z$ m# K/ [1 k0 s. `
  10.     latitude=float(data.iloc[i]['latitude'])    #分别将经纬度代入,计算与目标之间的欧氏距离
    . l. M8 V5 h4 B7 x! l
  11.     temp=geodesic((latitude1,longitude1), (latitude,longitude)).m   #temp对其遍历即可,这里对比各个地铁站的欧氏距离1 k$ p8 R/ {1 z& t, i(欢迎访问老王论坛:laowang.vip)
  12.     if temp<distance:
    8 t/ }! J7 e7 F5 z) t: K  o
  13.      distance=temp
    2 F0 d5 J0 n' q( ^  ]
  14.      nearest_subway=site1
    9 G3 y# X" z3 J) E  A
  15.      return nearest_subway  
复制代码
  1. def subway_line(start,end):    #创建点之间的距离4 @7 T5 z; W  [) U! F(欢迎访问老王论坛:laowang.vip)
  2.   file=open('graph.pkl','rb')
    7 C! [* v. M9 D" u  N: x
  3.   graph=pickle.load(file)   #现在我们有了各个地铁站之间的距离存储在graph
    6 X2 l, E. N. T2 M# M4 m7 C
  4.   costs={}    #创建节点的开销表,cost是指从start到该节点的距离' O% X% Q- `* r6 m4 d8 u(欢迎访问老王论坛:laowang.vip)
  5.   parents={}' ]# L$ x/ x- q  D/ Z(欢迎访问老王论坛:laowang.vip)
  6.   parents[end]=None* ^% c/ q! X# O+ L0 V5 e(欢迎访问老王论坛:laowang.vip)
  7.   for node in graph[start].keys():+ W" J1 o& f& t( `" W(欢迎访问老王论坛:laowang.vip)
  8.     costs[node]=float(graph[start][node])! q0 Z0 i3 n8 g- r1 v- `(欢迎访问老王论坛:laowang.vip)
  9.     parents[node]=start- |# }$ S( J$ Z2 {& p' j& c; R(欢迎访问老王论坛:laowang.vip)
  10.     costs[end]=float('inf')    #终点到起始点距离为无穷大7 K) m6 P0 C& `% d/ G: Q. X" ?. {(欢迎访问老王论坛:laowang.vip)
  11.     processed=[]      #记录处理过的节点list
    ( I# W# P/ j! N# i0 e
  12.     shortest_path=dijkstra(start,end,graph,costs,processed,parents)
    + O9 n$ p4 A) z
  13.     return shortest_path
复制代码
  1. #计算图中从start到end的最短路径; T+ o8 b) d) H8 X(欢迎访问老王论坛:laowang.vip)
  2. def dijkstra(start,end,graph,costs,processed,parents):
    8 @( Q. n  o+ i' q
  3.     #查询到目前开销最小的节点
    / d- J/ q. x3 l! y
  4.     node=find_lowest_cost_node(costs,processed)
    1 B+ \4 ?+ u% ]2 Q
  5.     #使用找到的开销最小节点,计算它的邻居是否可以通过它进行更新, G- v8 Z: T) S1 Z9 T(欢迎访问老王论坛:laowang.vip)
  6.     #如果所有的节点都在processed里面 就结束
    5 N, ^: q) R8 S5 W7 @
  7.     while node is not None:8 ?& \4 i6 U1 ?8 U8 _(欢迎访问老王论坛:laowang.vip)
  8.     #获取节点的cost
    / f# D. M; [: ^- A" v5 I! y' [
  9.       cost=costs[node]  #cost 是从node 到start的距离6 o& O1 E/ h; B(欢迎访问老王论坛:laowang.vip)
  10.       #获取节点的邻居
    ( P. T' s1 O. c" d
  11.       neighbors=graph[node]
    $ B  k0 v4 }6 i  [; O7 C7 S
  12.       #遍历所有的邻居,看是否可以通过它进行更新9 ]# l* u5 h% |) {' j(欢迎访问老王论坛:laowang.vip)
  13.       for neighbor in neighbors.keys():, z' S7 H. ~7 z5 P1 ^" u- c" M5 p5 J(欢迎访问老王论坛:laowang.vip)
  14.       #计算邻居到当前节点+当前节点的开销- h: F7 M" Q1 V5 `) v2 M5 r6 u(欢迎访问老王论坛:laowang.vip)
  15.         new_cost=cost+float(neighbors[neighbor])
    3 ^- W) Z. z7 S) f# m) c
  16.         if neighbor not in costs or new_cost<costs[neighbor]:
    9 w1 t  p! i. w4 h% _
  17.         costs[neighbor]=new_cost# E* m( u" y: O$ k" z5 \(欢迎访问老王论坛:laowang.vip)
  18.         #经过node到邻居的节点,cost最少( w7 U8 ^! {1 X3 B; d6 w(欢迎访问老王论坛:laowang.vip)
  19.         parents[neighbor]=node
    . \" u: V4 |- a+ P6 S, B
  20.         #将当前节点标记为已处理. J. s/ |* l/ i+ o% }+ [( u8 q(欢迎访问老王论坛:laowang.vip)
  21.   processed.append(node)
      T4 W6 m+ Z+ u4 Q
  22.   #下一步继续找U中最短距离的节点  costs=U,processed=S. b/ {8 D: b3 R) F(欢迎访问老王论坛:laowang.vip)
  23.   node=find_lowest_cost_node(costs,processed)
复制代码
  1. def find_lowest_cost_node(costs,processed):. s# L1 z' L# K, i, O(欢迎访问老王论坛:laowang.vip)
  2.     #初始化数据
    2 q9 K, `/ s: q
  3.   lowest_cost=float('inf') #初始化最小值为无穷大. H  D7 q4 H) i) R(欢迎访问老王论坛:laowang.vip)
  4.   lowest_cost_node=None
    % a0 c9 U: b% i: c
  5.     #遍历所有节点
    4 z+ O$ x  H# C0 J4 ^9 o: L+ u$ a5 _$ v
  6.   for node in costs:2 ]3 L% _  j- U(欢迎访问老王论坛:laowang.vip)
  7.     #如果该节点没有被处理( ]- ~; {0 s5 N4 l. e' A(欢迎访问老王论坛:laowang.vip)
  8.     if not node in processed:
    : o# r6 J, g/ _8 z/ ?. V
  9.       #如果当前的节点的开销比已经存在的开销小,那么更新该节点为最小开销的节点
    # l( a3 T" S! g# f. w
  10.       if costs[node]<lowest_cost:; U! B9 |( _3 t, R# R(欢迎访问老王论坛:laowang.vip)
  11.       lowest_cost=costs[node]
    1 J1 O' q6 A) @2 E1 |1 z# d
  12.       lowest_cost_node=node, m. @9 W' B( R6 M4 @(欢迎访问老王论坛:laowang.vip)
  13.     return lowest_cost_node
复制代码
上面这段基本上搬运的,主要是他代码已经写的很好了,注释也写的不错,但我写的时候爬虫调不出来(反爬虫技术可以的),最后是我手动去地图里找经纬度得到的结果。% x4 y# n0 ~3 ]2 x. a(欢迎访问老王论坛:laowang.vip)
引用:https://blog.csdn.net/fengdu78/article/details/111570695
; e. f1 h7 a0 ]* o6 y
) x' U: g3 u4 n! e6 {% t(欢迎访问老王论坛:laowang.vip)

8 }1 h, q* w2 W1 o8 \+ ~

3 M9 e# w/ N0 r# t  J% pA*算法:这个算法也是非常著名的算法,与Dijkstra算法相比,增加了启发式函数 ---- 启发函数的好坏直接决定了算法的效率和结果。由此衍生的D*(动态A算法)算法也被广泛运用于各类游戏中。D*的搜索效率高的原因就在于,当计划路径上某点被阻碍,因为是反向指针,可以定位到被堵节点的上一节点。也就是说只需重新搜索很小的一部分,其余部分仍然使用初始规划出的路径,大大提高了重规划的效率。1 j" f+ t9 r2 i2 f7 p% n9 \$ j( E(欢迎访问老王论坛:laowang.vip)
8 h: {7 I+ y2 a- e) k(欢迎访问老王论坛:laowang.vip)
) ?) Z  I- g- y' |  Z, V/ x1 V# C' |(欢迎访问老王论坛:laowang.vip)
额外补充-dfs&bfs逻辑
5 e$ q5 [# K0 M! |1 K( ]8 J深度搜索(dfs)和广度搜索(bfs)的算法逻辑可以说是最具有代表性的,基本任何有关于寻路的算法都没法绕开他俩。我担心可能没了解这2个算法直接去看Djkta和A*会有些懵逼: j; @+ v: a: u1 Q6 z( `(欢迎访问老王论坛:laowang.vip)

- C! m( D% k, j1 w( e) k! b- B深度搜索(dfs) * K% h8 v- B& J7 B4 l" L. r(欢迎访问老王论坛:laowang.vip)
5 O( u" V3 ~. V1 K(欢迎访问老王论坛:laowang.vip)
dfs就和它字面意思一样,是往更深的地方找(deepfound)4 F) G$ S6 A' f7 b2 [6 H. P8 z# M! w(欢迎访问老王论坛:laowang.vip)
它的核心思想很简单:
9 T- Z' X- N9 o! L8 c一直往前走,走不通就回头
. l& L9 V4 M( M6 x (, 下载次数: 6)
* |0 R# Z( m0 h/ |顺序?当然是长幼啦,有长立长无长立幼 (1会先找2而非6,在2时会先找4而非5 ,直到4发现3 发现无路可走再back回去)
1 X' G9 j4 n5 U: q/ e: u, h6 d大致伪代码如下5 E  N4 {1 r$ W( m4 ~. x(欢迎访问老王论坛:laowang.vip)
  1. input 地图  Y- C: R  {# j- t& @(欢迎访问老王论坛:laowang.vip)
  2. create 已经过点3 H8 F0 X" m3 ~# I9 m  g; e(欢迎访问老王论坛:laowang.vip)
  3. create 结果存储
    " i6 |8 {( `/ u& `: t
  4. : m5 @, r/ L0 B# {(欢迎访问老王论坛:laowang.vip)
  5. type node{% z, x( Q4 R. T; x(欢迎访问老王论坛:laowang.vip)
  6. node nextNode[];//下一节点们
    8 S3 V' a+ T" s0 [8 {% d
  7. nodeval;//节点标记物
    9 X6 X" c& e, P0 Q
  8. }
    6 u- r9 e, r" X( g
  9. . J3 I7 A' f$ q6 \( D(欢迎访问老王论坛:laowang.vip)
  10. 6 a( _4 y( K' }, v6 ]. q/ {- G; S1 i(欢迎访问老王论坛:laowang.vip)
  11. //这里开始是函数+ z' K  t' E4 g7 Y& i4 F' J: c(欢迎访问老王论坛:laowang.vip)
  12. fun dfs(node* nowPoint)+ w4 ~0 G7 w+ P/ t; O& ^* c" q* B(欢迎访问老王论坛:laowang.vip)
  13. {# X$ k' D& S2 |7 B0 j9 ?# s(欢迎访问老王论坛:laowang.vip)
  14. define u 为 nextNode[] size
    " `1 y' i5 z& `$ o, _$ o( o/ K# d) z# `
  15. int  key;% b' y4 E. }* a- \+ ?8 ~% f/ g8 z( c(欢迎访问老王论坛:laowang.vip)

  16. - N. K! W4 x  x: t
  17. for i in u {( T" f3 Z3 I: \/ ^( w# p8 Q- W(欢迎访问老王论坛:laowang.vip)
  18.       if (nowPoint.noteval == target)- ]* g4 [0 |! F2 A8 d(欢迎访问老王论坛:laowang.vip)
  19.         {
    / ^  ~( p$ y7 T* y' S' P6 @
  20.             结果存储[0] = nowPoint.noteval;
    9 ^8 [! y, ]  v) ]. j9 m2 A
  21.             return 0 ;  m7 O) U0 g: ^6 D" @. z' S(欢迎访问老王论坛:laowang.vip)
  22.         }  
    3 t. L2 G7 e( i+ j! N! u
  23.       else if( key = (dfs(nowPoint->nextNode[i])) != -1 ) //如果dfs这次没有返回负1(即 找到终点了)
    ! B- X5 k9 M6 L
  24.             {' @7 K& n( S9 M# O) a0 G/ k1 E! H" U(欢迎访问老王论坛:laowang.vip)
  25.                 结果存储[key] = nowPoint.noteval;
    8 M6 w  p  E8 }) Q2 t
  26.                 return key+1;         & P  D  a( J6 {" N/ [- s(欢迎访问老王论坛:laowang.vip)
  27.             }   
    + u/ ~8 I3 v! {+ `
  28.         else
    $ X& H% ~( Y* e& b
  29.             {
    / s/ E$ [) g5 I/ ]
  30.                 /********************/1 g$ x( O6 C. ^- g(欢迎访问老王论坛:laowang.vip)
  31.                 /**        nothing          **/6 j) J4 p4 \7 L1 O' e( o9 A3 M(欢迎访问老王论坛:laowang.vip)
  32.                 /********************// G2 s1 H7 b! s+ B6 ~(欢迎访问老王论坛:laowang.vip)
  33.             }    # T# ^  b- b! Z% ?8 @: g# {(欢迎访问老王论坛:laowang.vip)

  34. * i: M# M, K1 M
  35.         
    * z' ~+ g. ~1 M8 b; K* Q
  36.    }   
    5 K3 p/ t0 i. i6 B# H
  37.     return -1;
    9 w# ]8 D0 Z+ R7 r2 b3 H& n) A7 L
  38. }' S  I: t+ ~1 r5 g7 ~(欢迎访问老王论坛:laowang.vip)
复制代码
就那么短,你只需要确定是不是就行了
' L8 }9 o3 o6 C5 s7 q是不是很简单:p 但是这就是一个比较原始的寻路算法的模样-顺其自然流8 R. n0 k- j6 E" h- u. `1 M* s(欢迎访问老王论坛:laowang.vip)

# Q- v- y4 _# }! n/ |( n在dfs算法中,你需要做的就是 询问+上抛
. N( @% c1 w( w7 z4 J( o- ^' h3 x当然,dfs算法唯一能保证的就是‘找得到路’,这也是为什么纯粹的dfs算法不常用于生产环境中
$ m! ~% y0 W1 X5 `
. `3 `* p' K% e: R) r& |6 ~1 w/ u; H, a5 W(欢迎访问老王论坛:laowang.vip)
广度搜索(bfs)
8 z9 E  L( N0 h8 d. k, ]- P; C知道深度,广度就很容易联想了 先找周围嘛 无论如何,先找周围* I' z3 ?* g; D1 `0 a: P(欢迎访问老王论坛:laowang.vip)
(, 下载次数: 4)
$ ~5 ^6 M. |9 Y3 u- H) W% l这里不进行代码补充了,只简单地说一下逻辑" x& T: w  |9 g(欢迎访问老王论坛:laowang.vip)

; }8 o% Z! \/ B+ f这个算法分以下几步:
+ K9 Y3 Z( {2 o# x  Z# @, r0,准备一个队列(就是那个queue),然后丢入我们的起点 命运的齿轮开始拨动% }1 J& d; O; _7 t(欢迎访问老王论坛:laowang.vip)

6 |& K: P* B. p; o1,询问当前节点是否终点?) c7 e5 h! N9 O- B( A/ c/ F2 a(欢迎访问老王论坛:laowang.vip)
2,将自己的nextNode 塞入队列中(除了访问过的)
# S) z, i% D8 ?  I! e5 H- Y. ^3,从队列里output一个节点,作为下一个‘当前节点’" Q# s# N. p4 k0 N/ z, r(欢迎访问老王论坛:laowang.vip)

/ a! \' N* q" r& }然后就是循环1~3
% \- i$ r+ t/ d/ `- ]/ Y" L2 y6 y: M. c) Y3 R! ~(欢迎访问老王论坛:laowang.vip)
是不是很简单?8 z) R4 M, ~% v; M- o* N(欢迎访问老王论坛:laowang.vip)

5 `6 Y: v$ Z& S这2个算法都属于随性流,一个适合终点远一个适合终点近。但无论如何这俩都暂时没有比较最优的功能
1 z. W2 Q! ^- }3 [7 y因为他们刚~满~十~八~岁~的审敛条件就只是找得到路
: d9 t1 x1 o/ D1 Y
# u# c, z( }9 X: L8 T但你可以发现哦?如果将dfs的‘长幼判断’换成‘最优判断’,将呆值传递换为矩阵存储 就是dj算法了诶(a*也是类似的)5 v% m4 {5 V( g6 g( O(欢迎访问老王论坛:laowang.vip)
而bfs作为‘扩散式搜索’显然地在进行多点寻路时效用更加明显2 F1 Z# B6 H5 p5 X+ V' \6 c(欢迎访问老王论坛:laowang.vip)
如果觉得寻路算法很难的话,不妨先从dfs&bfs开始了解- y* V* O7 c: b/ J(欢迎访问老王论坛:laowang.vip)

8 }" ?" z! L% a/ i3 O7 \3 G6 E6 N1 n# p* i(欢迎访问老王论坛:laowang.vip)
! a( b" o7 I# }4 \9 t(欢迎访问老王论坛:laowang.vip)

8 f! X' ?3 ]- f) M
作者: navebayes    时间: 2023-12-25 20:11
标题: 修改修改
本帖最后由 navebayes 于 2023-12-25 20:14 编辑
5 w6 u: {$ u# F
; m( r, W2 A( N/ D' ^$ N9 x- P! \申请失败,原因:对算法本身描述过少,请更具体地说明算法的运作逻辑和方式,如果可以最好给出部分低代码% u7 f# s; \6 D6 K(欢迎访问老王论坛:laowang.vip)
, D  Y4 \+ C6 I$ ~' L: q; i( W8 T(欢迎访问老王论坛:laowang.vip)
ps:只要做滴好,王爷有赏啊
作者: Applcu    时间: 2023-12-25 20:19
navebayes 发表于 2023-12-25 20:11
+ U2 c9 h$ t# A+ g/ G5 `申请失败,原因:对算法本身描述过少,请更具体地说明算法的运作逻辑和方式,如果可以最好给出部分低代码6 l4 {4 _9 S$ M" }" M8 Q! u! f(欢迎访问老王论坛:laowang.vip)

" |4 t6 H8 Y+ K& g7 I- Y ...

4 V: Q4 W; g9 n; x  h我在想怎么算说明运作逻辑.....真贴上去么?这个编辑器到底怎么用啊& t) E9 V8 n0 c/ d; T1 M' [( G  W* J(欢迎访问老王论坛:laowang.vip)

作者: 昔有佳人公孙氏    时间: 2023-12-25 20:25
navebayes 发表于 2023-12-25 20:11" M% [$ T; U8 k3 D  ]) e(欢迎访问老王论坛:laowang.vip)
申请失败,原因:对算法本身描述过少,请更具体地说明算法的运作逻辑和方式,如果可以最好给出部分低代码2 A/ y, P, M' q7 e% W& T(欢迎访问老王论坛:laowang.vip)
1 S+ F" \/ g: J' S7 B  e( e1 G8 w; b(欢迎访问老王论坛:laowang.vip)
...

# p! t6 v. {& A" J5 r3 y: {  k啊这。不如解释一下单源最短路径问题中对于负权值和负权值回路为什么不能使用上述算法. S4 `7 y3 H  P4 g(欢迎访问老王论坛:laowang.vip)
  J  J, I* h7 i' p4 C& L(欢迎访问老王论坛:laowang.vip)
这玩意考试考得头昏脑涨,我tm 深度生成树画错了,越想越气 怎么会这么蠢8 x( }2 b- R6 I8 V0 s(欢迎访问老王论坛:laowang.vip)

作者: navebayes    时间: 2023-12-25 20:31
Applcu 发表于 2023-12-25 20:19% o+ z( G; y% z/ w) l& L(欢迎访问老王论坛:laowang.vip)
我在想怎么算说明运作逻辑.....真贴上去么?这个编辑器到底怎么用啊  F" n2 u- z) h9 B7 v(欢迎访问老王论坛:laowang.vip)
...
/ g- I- N$ U( `9 I(欢迎访问老王论坛:laowang.vip)
有一个代码框功能,可以用那个。主要编辑的话建议用正八经的md编辑器(我用的是国产的typora)
作者: navebayes    时间: 2023-12-25 20:35
昔有佳人公孙氏 发表于 2023-12-25 20:253 d9 i6 z2 }/ S# u(欢迎访问老王论坛:laowang.vip)
啊这。不如解释一下单源最短路径问题中对于负权值和负权值回路为什么不能使用上述算法% h6 w+ T+ u8 g; s+ Y  m6 y(欢迎访问老王论坛:laowang.vip)

5 F1 w$ Q7 H  ^) n这玩意考试考得头 ...

8 |. R: ~4 `6 f2 f) }看作者本人嘛,我不想干涉思路..9 d# {) o  d  o* \& @(欢迎访问老王论坛:laowang.vip)
(程序:哥们这可不是什么负权圈,这是时空之门啊啊啊啊啊(然后获得了每过一年减一岁的黄金体验))
作者: Applcu    时间: 2023-12-25 20:43
昔有佳人公孙氏 发表于 2023-12-25 20:25, y5 K- k! j1 l* j" Z% H& d(欢迎访问老王论坛:laowang.vip)
啊这。不如解释一下单源最短路径问题中对于负权值和负权值回路为什么不能使用上述算法
9 t1 c8 A* W7 s* |$ q$ |
% J* H; U* A  K这玩意考试考得头 ...
$ p/ }7 R$ ~0 N: a(欢迎访问老王论坛:laowang.vip)
这应该是考专业课考破防了9 T8 X: y6 h6 I3 t% a(欢迎访问老王论坛:laowang.vip)

作者: Applcu    时间: 2023-12-25 20:48
昔有佳人公孙氏 发表于 2023-12-25 20:25
! K4 `1 C* k% d啊这。不如解释一下单源最短路径问题中对于负权值和负权值回路为什么不能使用上述算法' |6 C1 Y1 Z3 t0 t; s(欢迎访问老王论坛:laowang.vip)

5 Y1 d( P; U& x/ g2 {* P/ B$ d这玩意考试考得头 ...

  r# p( K" B& ^7 j& _负权不就卡bug了么,越来越低就成环了
/ z! B+ r6 j: o' p8 E( G5 ]7 D" Y
作者: navebayes    时间: 2023-12-25 20:56
Applcu 发表于 2023-12-25 20:48
4 L; m* R* N# s0 s- Y8 x负权不就卡bug了么,越来越低就成环了

: s: s) q4 y( Y% @: `6 r宝宝,把剩下的内容补上嘛
作者: Applcu    时间: 2023-12-25 21:15
navebayes 发表于 2023-12-25 20:56; t4 G7 A, b% [/ w% q% [(欢迎访问老王论坛:laowang.vip)
宝宝,把剩下的内容补上嘛
- U: M, l+ n- C(欢迎访问老王论坛:laowang.vip)
真是男童啊.....
* |1 Z' M1 R: {4 e& h6 N' F
作者: navebayes    时间: 2023-12-25 21:37
Applcu 发表于 2023-12-25 21:15# v2 t6 M8 Q- V$ Q(欢迎访问老王论坛:laowang.vip)
真是男童啊.....

/ W4 T7 r2 o- }, F诽谤管理封七天
作者: Applcu    时间: 2023-12-25 21:58
先说说个人对于Dijkstra算法设计地铁线路规划:# r; a& C. O" L9 ?2 u/ ](欢迎访问老王论坛:laowang.vip)
1.首先用爬虫爬到该城市的地铁网络,包含站点名称,该站点经纬度和线路图,并生成excel表格。用该excel表格生成pickle文件,方便直接调用。
2 F7 d4 e+ ^; ^# S) P  R( n0 I+ F4 W! m2.注册高德地图开发者账号(该功能需要实名),得到一个key用于调用api(每日上限100次,超过付费,我调试到后面不让我调试了...)
5 l& [' d) }  w& @$ i3.输入始发地和目的地,并通过api返回两个位置的经纬度坐标。
8 G5 ]3 I" n4 u  y) ], z% x4.比较两地理位置之间的最近地铁站,并根据Dijkstra算法实现路径规划。) x2 C4 B0 U- ~(欢迎访问老王论坛:laowang.vip)
5.Dijkstra算法的本质就是不断选择新顶点并更新已处理表,并将他和邻居节点进行比对,当所有节点都被处理后即为最短路径; ]- N5 ?: `' E  F4 q/ V+ G" A(欢迎访问老王论坛:laowang.vip)
至此,已初步完成具体工作流程。
1 k, m' I6 D& j# a, L6 S" ~; {
  1. def get_nearest_subway(data,longitude1,latitude1):
    . y7 G8 ]5 G  S8 h( Z) s$ w7 {
  2.     #找最近的地铁站
    4 B" s2 l! S: p1 H) n  J8 i
  3.     longitude1=float(longitude1)6 l! w, O- {- X2 Y7 C(欢迎访问老王论坛:laowang.vip)
  4.     latitude1=float(latitude1)2 T" K' [- _! S" ~, ?5 |" Z(欢迎访问老王论坛:laowang.vip)
  5.     distance=float('inf')
    % {! [7 V$ ]. c$ U* k9 `
  6.     nearest_subway=None
    5 l% R8 Z" R5 z! K
  7.     for i in range(data.shape[0]):
    ; N* s: O2 c: r$ j
  8.   site1=data.iloc[i]['name']    + s5 @9 d0 H  }& V3 Q(欢迎访问老王论坛:laowang.vip)
  9.   longitude=float(data.iloc[i]['longitude'])% r! F& O0 K; p  U, Q8 ^(欢迎访问老王论坛:laowang.vip)
  10.   latitude=float(data.iloc[i]['latitude'])    #分别将经纬度代入,计算与目标之间的欧氏距离6 [+ k  L! I" J9 p* Z3 Y(欢迎访问老王论坛:laowang.vip)
  11.   temp=geodesic((latitude1,longitude1), (latitude,longitude)).m   #temp对其遍历即可,这里对比各个地铁站的欧氏距离
    0 V4 ]1 c( [2 W2 P# t/ @3 I
  12.   if temp<distance:- W% y+ z' B9 Q3 }' a3 t(欢迎访问老王论坛:laowang.vip)
  13.     distance=temp
    ) I$ _7 E1 i3 l  D/ T0 c  P# r
  14.     nearest_subway=site1, S- D) ?2 a  V(欢迎访问老王论坛:laowang.vip)
  15.     return nearest_subway  
复制代码
  1. def subway_line(start,end):    #创建点之间的距离
    , S+ n6 M) [& _" M. q8 C2 q
  2.     file=open('graph.pkl','rb')
    ; N8 i" m& Y: D  y
  3.     graph=pickle.load(file)   #现在我们有了各个地铁站之间的距离存储在graph
      j8 w$ b8 x  Z& W
  4.     costs={}    #创建节点的开销表,cost是指从start到该节点的距离, h+ ?9 u/ N! [4 E+ V(欢迎访问老王论坛:laowang.vip)
  5.     parents={}$ R  ^' }5 Z% @% a( K(欢迎访问老王论坛:laowang.vip)
  6.     parents[end]=None; K6 Z  U' _7 u, V+ A$ g(欢迎访问老王论坛:laowang.vip)
  7.     for node in graph[start].keys():
    $ t0 i* |' N( ^, @
  8.   costs[node]=float(graph[start][node])
    2 }4 R& x. ~& N7 [' }5 |
  9.   parents[node]=start8 i; Y& a8 F# E2 ~8 Z(欢迎访问老王论坛:laowang.vip)
  10.     costs[end]=float('inf')    #终点到起始点距离为无穷大
    : b7 B' O6 A& s7 Q; G+ c" I
  11.     processed=[]      #记录处理过的节点list3 _5 m# r8 `% g2 Q(欢迎访问老王论坛:laowang.vip)
  12.     shortest_path=dijkstra(start,end,graph,costs,processed,parents)  Y. P0 d" [6 R2 A8 g) q$ O9 f) {(欢迎访问老王论坛:laowang.vip)
  13.     return shortest_path
复制代码
  1. #计算图中从start到end的最短路径
    % ~7 A' M! i4 z9 J2 N5 g" G
  2. def dijkstra(start,end,graph,costs,processed,parents):
    & U3 p: _3 I# g( t: D
  3.     #查询到目前开销最小的节点
    & b# W# r/ p1 l
  4.     node=find_lowest_cost_node(costs,processed)8 }0 l! ?! M7 D1 c( S(欢迎访问老王论坛:laowang.vip)
  5.     #使用找到的开销最小节点,计算它的邻居是否可以通过它进行更新9 H- h$ `2 g: F; ^(欢迎访问老王论坛:laowang.vip)
  6.     #如果所有的节点都在processed里面 就结束
    % q5 p; y6 R* q- ]% k; @
  7.     while node is not None:
    1 I# Z) P$ ^' n/ L+ B2 D
  8.   #获取节点的cost
    6 I! g! x7 t; p0 F$ ]& T( _
  9.   cost=costs[node]  #cost 是从node 到start的距离$ [& t' s( j, _(欢迎访问老王论坛:laowang.vip)
  10.   #获取节点的邻居
    8 U6 u; P2 k5 F* [9 Q4 l
  11.   neighbors=graph[node]
    2 _! I. {# N# L8 w& A2 w; q
  12.   #遍历所有的邻居,看是否可以通过它进行更新( }2 R3 A! r, f5 X' ?: l# I+ b(欢迎访问老王论坛:laowang.vip)
  13.   for neighbor in neighbors.keys():
    ( U; U% v; |* u. p' W- M/ Y0 L, U4 N5 L
  14.     #计算邻居到当前节点+当前节点的开销
    9 b( A$ v) T& B3 I4 e
  15.     new_cost=cost+float(neighbors[neighbor])' ]5 V2 x* n  ?# G; I  N) g8 K$ J(欢迎访问老王论坛:laowang.vip)
  16.     if neighbor not in costs or new_cost<costs[neighbor]:6 E+ U- [2 |6 [' H' g(欢迎访问老王论坛:laowang.vip)
  17.       costs[neighbor]=new_cost0 J8 j5 q" |# C" g+ e( F; U(欢迎访问老王论坛:laowang.vip)
  18.       #经过node到邻居的节点,cost最少' ], f8 f( t& ^$ I% i) a(欢迎访问老王论坛:laowang.vip)
  19.       parents[neighbor]=node" C6 `9 [) j  }: Q; w) b6 y6 [(欢迎访问老王论坛:laowang.vip)
  20.   #将当前节点标记为已处理* c  j1 `& Q7 b(欢迎访问老王论坛:laowang.vip)
  21.   processed.append(node)
    7 ]3 u! C3 p3 _; g( V
  22.   #下一步继续找U中最短距离的节点  costs=U,processed=S8 x' R# Z; I) H2 M$ B2 T(欢迎访问老王论坛:laowang.vip)
  23.   node=find_lowest_cost_node(costs,processed)
复制代码

" M) N( R! L8 {; m6 d# U
" A4 T0 A( l6 N* U6 n% t# x
  1. def find_lowest_cost_node(costs,processed):
    ( o/ O% k/ j1 L& }1 h: E) `
  2.     #初始化数据5 D, E  S& x4 k, b0 R! _; f2 O/ p(欢迎访问老王论坛:laowang.vip)
  3.     lowest_cost=float('inf') #初始化最小值为无穷大
    7 B& Z7 [$ a% t
  4.     lowest_cost_node=None
    0 F3 [$ R0 w0 n& N! E
  5.     #遍历所有节点
    1 O4 [% w6 Q& T2 O* P
  6.     for node in costs:; r& A  I# @7 T& Q* y3 ]/ F7 M* Y4 P3 ~6 H(欢迎访问老王论坛:laowang.vip)
  7.   #如果该节点没有被处理( D6 h: L; y2 N# D* @, O! E(欢迎访问老王论坛:laowang.vip)
  8.   if not node in processed:
    & O4 Y( [2 Y, M+ a5 u4 S
  9.     #如果当前的节点的开销比已经存在的开销小,那么更新该节点为最小开销的节点
    2 ^; q" w( h- [" F8 S
  10.     if costs[node]<lowest_cost:
    8 u- K- C7 Z+ f& X1 P! K
  11.       lowest_cost=costs[node]
    + w& ~5 V" e3 t) p* x. O+ V* R% R5 i
  12.       lowest_cost_node=node
    . ]2 m: {- P& I  ]8 [3 Q' u2 ?; K+ p
  13.     return lowest_cost_node
复制代码
上面这段基本上搬运的,主要是他代码已经写的很好了,注释也写的不错,但我写的时候爬虫调不出来(反爬虫技术可以的),最后是我手动去地图里找经纬度得到的结果。. W7 m: S. A6 M! K* ]* S0 R3 J) x(欢迎访问老王论坛:laowang.vip)
引用:https://blog.csdn.net/fengdu78/article/details/111570695
2 B& w) Z. e, I; W3 [2 G: @
作者: navebayes    时间: 2023-12-25 22:34
Applcu 发表于 2023-12-25 21:584 ~4 M% U* w# D9 G7 R- J2 q6 H- e' t(欢迎访问老王论坛:laowang.vip)
先说说个人对于Dijkstra算法设计地铁线路规划:; O/ E8 N1 ~; [- b(欢迎访问老王论坛:laowang.vip)
1.首先用爬虫爬到该城市的地铁网络,包含站点名称,该站点 ...
. \9 w; H1 U7 r0 I" w1 `; _(欢迎访问老王论坛:laowang.vip)
可以加入正文喵0 j% O0 U6 I; g1 \! Q: k(欢迎访问老王论坛:laowang.vip)

作者: Applcu    时间: 2023-12-25 22:42
昔有佳人公孙氏 发表于 2023-12-25 20:25+ v1 B3 f6 J4 R' T, Z(欢迎访问老王论坛:laowang.vip)
啊这。不如解释一下单源最短路径问题中对于负权值和负权值回路为什么不能使用上述算法& ?1 O1 Q' |  f5 C' k# H" \; _6 O(欢迎访问老王论坛:laowang.vip)
( [4 F8 P( [- u(欢迎访问老王论坛:laowang.vip)
这玩意考试考得头 ...
  A/ e( v7 H8 ]5 m% n2 r- F(欢迎访问老王论坛:laowang.vip)
我也头大了.....但本质还是因为Dijkstra算法认为,如果有一条最短路线可以直达目的地,那么从旁边走另外的路将会直接不考虑,但在负权边这里,反而会减小cost,所以Dijkstra算法失效了,因为无法发现这条最短的路径
# r  e( k- X+ Z5 O1 G# A
作者: Applcu    时间: 2023-12-25 22:51
navebayes 发表于 2023-12-25 22:348 c. q& C6 N+ x! N8 s) d. S) s(欢迎访问老王论坛:laowang.vip)
可以加入正文喵
# u3 _! t. k* m7 h(欢迎访问老王论坛:laowang.vip)
加了加了3 M' X; J& O" Z5 L(欢迎访问老王论坛:laowang.vip)

作者: navebayes    时间: 2023-12-25 23:02
Applcu 发表于 2023-12-25 22:51
6 F) C2 a/ T/ c5 d加了加了

1 Z( l  z- n, {. A7 y介意让我改一下吗  c. E2 F! A1 I- s9 `/ V& v(欢迎访问老王论坛:laowang.vip)

作者: 昔有佳人公孙氏    时间: 2023-12-25 23:08
其实目前,本科生能接触到的寻路算法 无外乎迪杰斯特拉和弗洛伊德 一个不吃负值 一个不吃负环3 u; D. q* m' K$ }! Y- N: ^(欢迎访问老王论坛:laowang.vip)
但其实寻找最短路径的算法里还有很知名的黏菌算法。
5 E7 U* f7 I1 n& n8 ?- u8 B% L3 D有兴趣的可以去B站搜搜黏菌走迷宫,看看在大自然顶级的算法编辑下的单源最短路径问题的解法8 t3 s9 `+ j& l(欢迎访问老王论坛:laowang.vip)
不是说将奖励放置位置对应于日本的各大城市,两天内的黏菌路线就基本和目前日本的城市规划大致相似了吗,当然不太严谨是真的
% z7 ]  M. E4 I2 F4 \. C& O就好像楼主说的做了地铁最短路径规划, 这玩意我舍友和你类似,她做的事全国铁路路径规划,涉及到价格,时间,反正做到最后是你输入起始地址和目的地,就能得出花费最少,时间最少,转站最少的路线,C++课设 我记得很清楚,我记得老师说的评价是,如果再加上运筹学的内容,说不定可以当毕业论文了,不出意外她拿了满分。
作者: Applcu    时间: 2023-12-25 23:28
昔有佳人公孙氏 发表于 2023-12-25 23:08
/ p: Q+ G9 j$ `! f$ \其实目前,本科生能接触到的寻路算法 无外乎迪杰斯特拉和弗洛伊德 一个不吃负值 一个不吃负环% j% O+ ?0 c4 Y! J; s& A(欢迎访问老王论坛:laowang.vip)
但其实寻找最 ...
- ?  K1 C+ u  k: K/ A" n(欢迎访问老王论坛:laowang.vip)
黏菌那个早有耳闻,确实是大自然的力量。我之后还想写点加密算法,比如AES,RSA,ECC之类的,其实这个地铁的算法也是我的一个课设,我大概花了两天就搞完了,我的主专业课是自控/单片机/数电/模电/嵌入式之类的,更偏自动化这个方向,算法我研究的不深。这个当毕业论文可能还是有一些勉强的,个人感觉工科是要做出一点实物的东西,当然不同学校可能要求不尽相同。5 i& O  r  {( T9 Z3 ](欢迎访问老王论坛:laowang.vip)

4 P& R& a  U) G$ b- q3 p
9 T7 l! {8 m; b& b3 E% u" s8 @- l
作者: Applcu    时间: 2023-12-25 23:30
navebayes 发表于 2023-12-25 23:02
* v) B4 m& \9 o& r介意让我改一下吗
: F8 ^) V1 d# B( ](欢迎访问老王论坛:laowang.vip)
可以可以
$ F( y5 h& f3 K
作者: navebayes    时间: 2023-12-26 12:03
Applcu 发表于 2023-12-25 23:304 |' b/ l  s! P" A(欢迎访问老王论坛:laowang.vip)
可以可以
7 @" p0 \; H, y3 ~(欢迎访问老王论坛:laowang.vip)
排版改了下喵,东西加好了喵
) T' D5 N' L. f+ i/ q/ v( A: u
作者: Applcu    时间: 2023-12-26 13:37
navebayes 发表于 2023-12-26 12:03
; U5 l9 W# K: v: U排版改了下喵,东西加好了喵

2 k, k6 F7 a0 m好好好,大概就这样吧建议打钱) G& x3 k9 [9 Y# i(欢迎访问老王论坛:laowang.vip)

作者: navebayes    时间: 2023-12-26 13:52
标题: 再加加些吧
本帖最后由 navebayes 于 2023-12-27 17:11 编辑 ) t+ V: I. H% S1 R) g3 R9 k(欢迎访问老王论坛:laowang.vip)
: Z8 M! w; k: X3 R(欢迎访问老王论坛:laowang.vip)
基础50可读50排版50内容120其他40共计235+45+30=310
作者: navebayes    时间: 2023-12-26 13:56
Applcu 发表于 2023-12-26 13:37
" g9 [! m( z# a3 S" _. j1 Q好好好,大概就这样吧建议打钱
8 m% _+ E% S/ |# e& a(欢迎访问老王论坛:laowang.vip)
下次可以的话写详细些..比如算法这类最好有深有浅
作者: qwer20021125    时间: 2023-12-26 20:15
很难想象居然在这里看到了这种文章,点赞
作者: Applcu    时间: 2023-12-26 22:28
navebayes 发表于 2023-12-26 13:569 [1 B. G4 I$ N' }(欢迎访问老王论坛:laowang.vip)
下次可以的话写详细些..比如算法这类最好有深有浅
, i0 D0 k( U& C# C( x+ f(欢迎访问老王论坛:laowang.vip)
好的,下次改进一下
0 S8 B- B; N% M4 A: p' M8 k
作者: Applcu    时间: 2023-12-26 22:30
qwer20021125 发表于 2023-12-26 20:15
, m$ L  v+ G" S) v+ f! d很难想象居然在这里看到了这种文章,点赞

  B( r& |9 A" A' u7 A6 t' P/ r你可以在ghs的网站看到高数的视频,那肯定也能在这看到算法类帖子
) d( m. M% f9 Q4 }( V  W
作者: navebayes    时间: 2023-12-27 17:14
Applcu 发表于 2023-12-26 22:28
# u& ^0 V) {* E+ x1 M4 b" W. Z( F  p好的,下次改进一下

, n& p2 z7 X" @  r2 u今天给你们加钱了喵,主要是感觉原来的发的还是有些少
6 C6 n* w. j; h
作者: 六道骸    时间: 2023-12-29 00:45
太专业看不懂,,,
作者: Applcu    时间: 2023-12-29 01:22
六道骸 发表于 2023-12-29 00:45
# P' ]6 T# V& B# q. t0 n* `7 M太专业看不懂,,,

, m2 X9 ]4 S0 @& m8 O6 T这个还是要对算法有一定了解才能看懂% B) a4 w. j" D. e0 `(欢迎访问老王论坛:laowang.vip)

作者: gaogao0621    时间: 2024-3-12 21:03
我是一个初中OIer,如有错误请指出,欢迎讨论7 L( _, Z5 r+ m1 r% l* J(欢迎访问老王论坛:laowang.vip)
我记得之前好像看主要地图的寻路算法是A*?如果没记错的话
: f: H8 g$ n: L  s' s  ^7 U8 \; G4 O$ G$ A(欢迎访问老王论坛:laowang.vip)
有几点建议:+ Z" Z- |+ l  p% \3 h(欢迎访问老王论坛:laowang.vip)
1.具体算法实现可以用CPP,Python太慢了,尤其是要处理百万/千万级别的数据时,可以用python爬取数据然后由cpp进行相应处理,这样的好处是大幅减少了时间且使不会特别麻烦(CPP的网络爬虫实现太麻烦,且各种配置环境很难受)不过如果数据量不是很大的话用py很省开发时间(/ y6 T% {0 z! O' K$ U# m' ~1 K(欢迎访问老王论坛:laowang.vip)
2.关于实现算法我个人更推荐A*,由于其是启发式的,时间复杂度比Dij低,也能省下很长时间(不过也要看数据量,有些时候IDA*比A*好)至于您说的D*很抱歉我没有接触过这个算法,不予评价" u# C# N' l5 ?% A(欢迎访问老王论坛:laowang.vip)
! E+ J. C  x3 l(欢迎访问老王论坛:laowang.vip)
如果有很多很多线路要查询的话还可以加个多线程优化,这个用py的threading更容易些,当然cpp也不是不行+ B6 W# A* _  x2 p(欢迎访问老王论坛:laowang.vip)

- V% n# E* P0 p* D& _; x% {0 e- ~3 V$ j




欢迎光临 老王论坛 (https://laowangwir455.vip/) Powered by Discuz! X3.4