某种工程设备的役龄为 4 年, 每年年初都面临着是否更新的问题: 若卖旧买新, 就要支付一定的购置费用; 若继续使用, 则要支付更多的维护费用, 且使用年限越长维护费用越多. 役龄期内每年的年初购置价格, 当年维护费用及年末剩余净值如下表所示. 为该设备制定一个 4 年役龄期内的更新计划, 使总的支付费用最少.
年份 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
年初购置价格 (万元) | 25 | 26 | 28 | 31 |
当年维护费用 (万元) | 10 | 14 | 18 | 26 |
年末剩余净值 (万元) | 20 | 16 | 13 | 11 |
可以把这个问题化为图论中的最短路问题.
构造赋权有向图 D = ( V , A , W ) D=(V, A, W) D=(V,A,W), 其中顶点集 V = { v 1 , v 2 , ⋯ , v 5 } V=\left\{v_{1}, v_{2}, \cdots, v_{5}\right\} V={v1,v2,⋯,v5}, 这里 v i v_{i} vi ( i = 1 , 2 , 3 , 4 ) (i=1,2,3,4) (i=1,2,3,4) 表示第 i i i 年年初的时刻, v 5 v_{5} v5 表示第 4 年年末的时刻, A A A 为边集, 邻接矩阵 W = ( w i j ) 5 × 5 W=\left(w_{i j}\right)_{5 \times 5} W=(wij)5×5, 这里 w i j w_{i j} wij 为第 i i i 年年初至第 j j j 年年初 (或 j − 1 j-1 j−1 年年末) 期间所支付的费用, 计算公式为
w i j = p i + ∑ k = 1 j − i a k − r j − i , w_{i j}=p_{i}+\sum_{k=1}^{j-i} a_{k}-r_{j-i}, wij=pi+k=1∑j−iak−rj−i,
其中 p i p_{i} pi 为第 i i i 年年初的购置价格, a k a_{k} ak 为使用到第 k k k 年当年的维护费用, r i r_{i} ri 为使用 i i i 年旧设备的出售价格.
则邻接矩阵
W = [ 0 15 33 54 82 ∞ 0 16 34 55 ∞ ∞ 0 18 36 ∞ ∞ ∞ 0 21 ∞ ∞ ∞ ∞ 0 ] . W=\left[\begin{array}{ccccc} 0 & 15 & 33 & 54 & 82 \\ \infty & 0 & 16 & 34 & 55 \\ \infty & \infty & 0 & 18 & 36 \\ \infty & \infty & \infty & 0 & 21 \\ \infty & \infty & \infty & \infty & 0 \end{array}\right] . W=⎣⎢⎢⎢⎢⎡0∞∞∞∞150∞∞∞33160∞∞5434180∞825536210⎦⎥⎥⎥⎥⎤.
则制定总的支付费用最小的设备更新计划, 就是求有向图 D D D 从顶点 v 1 v_{1} v1 到页点 v 5 v_{5} v5 的最短路.
import numpy as np
import networkx as nx
import pylab as plt
p=[25,26,28,31]; a=[10,14,18,26]; r=[20,16,13,11]
b=np.zeros((5,5)); #初始化邻接矩阵
for i in range(5):
for j in range(i+1,5):
b[i,j]=p[i]+np.sum(a[0:j-i])-r[j-i-1];
print(b)
G=nx.DiGraph(b)
p=nx.dijkstra_path(G, source=0, target=4, weight='weight') #求最短路径;
print("最短路径为:",np.array(p)+1) #python下标从0开始
d=nx.dijkstra_path_length(G, 0, 4, weight='weight') #求最短距离
print("所求的费用最小值为:",d)
s=dict(zip(range(5),range(1,6))) #构造用于顶点标注的标号字典
plt.rc('font',size=16)
pos=nx.shell_layout(G) #设置布局
w=nx.get_edge_attributes(G,'weight')
nx.draw(G,pos,font_weight='bold',labels=s,node_color='r')
nx.draw_networkx_edge_labels(G,pos,edge_labels=w)
path_edges=list(zip(p,p[1:]))
nx.draw_networkx_edges(G,pos,edgelist=path_edges,edge_color='r',width=3) #画出最短路径
#plt.savefig("figure10_9.png",pdi=500);
plt.show()
[[ 0. 15. 33. 54. 82.]
[ 0. 0. 16. 34. 55.]
[ 0. 0. 0. 18. 36.]
[ 0. 0. 0. 0. 21.]
[ 0. 0. 0. 0. 0.]]
最短路径为: [1 2 3 5]
所求的费用最小值为: 67.0
求得 v 1 v_{1} v1 到 v 5 v_{5} v5 的最短路径为 v 1 → v 2 → v 3 → v 5 v_{1} \rightarrow v_{2} \rightarrow v_{3} \rightarrow v_{5} v1→v2→v3→v5, 最短路径的长度为67. 即设备更新计划为第1年年初买进新设备, 使用到第 1 年年底, 第 2 年年初购进新设备, 使用到第 2 年年底, 第 3 年年初再购进新设备, 使用到第 4 年年底.
重心问题指有些公共服务设施 (例如邮局, 学校等) 的选址, 要求设施到所有服务对象点的距离总和最小. 一般要考虑人口密度问题, 或者全体被服务对象来往的总路程最短. 例如下面的问题:
某矿区有六个产矿点, 如图所示, 已知各产矿点每天的产矿量 (标在图中的各顶点旁) 为 q i ( i = 1 , 2 , ⋯ , 6 ) q_{i}(i=1,2, \cdots, 6) qi(i=1,2,⋯,6) 吨, 现要从这六个产矿点选一个来建造选矿厂, 问应选在哪个产矿点, 才能使各产矿点所产的矿石运到选矿厂所在地的总运力 (吨·公里) 最小.
令 d i j ( i , j = 1 , 2 , ⋯ , 6 ) d_{i j}(i, j=1,2, \cdots, 6) dij(i,j=1,2,⋯,6) 表示顶点 v i v_{i} vi 与 v j v_{j} vj 之间的距离. 若选矿厂设在 v i v_{i} vi 并且各产矿点到选矿厂的总运力为 m i m_{i} mi, 则确定选矿厂的位置就转化为求 m k m_{k} mk, 使得 m k = min 1 ≤ i ≤ 6 m i m_{k}=\min _{1 \leq i \leq 6} m_{i} mk=min1≤i≤6mi.
由于各产矿点到选矿厂的总运力依赖于任意两顶点之间的距离, 即任意两顶点之间最短路的长度, 因此可首先利用 Dijkstra (或 Floyd) 算法求出所有顶点对之间的最短距离, 然后计算出顶点 v i v_{i} vi 设立选矿厂时各产矿点到 v i v_{i} vi 的总运力
m i = ∑ j = 1 6 q j d i j , i = 1 , 2 , ⋯ , 6. m_{i}=\sum_{j=1}^{6} q_{j} d_{i j}, \quad i=1,2, \cdots, 6. mi=j=1∑6qjdij,i=1,2,⋯,6.
最后利用 min 1 ≤ i ≤ 6 m i \min _{1 \leq i \leq 6} m_{i} min1≤i≤6mi 选择设置选矿厂的位置.
计算的 Python 程序如下:
import numpy as np
import networkx as nx
List=[(1,2,20),(1,5,15),(2,3,20),(2,4,40),
(2,5,25),(3,4,30),(3,5,10),(5,6,15)]
G=nx.Graph()
G.add_nodes_from(range(1,7))
G.add_weighted_edges_from(List)
c=dict(nx.shortest_path_length(G,weight='weight'))
d=np.zeros((6,6))
for i in range(1,7):
for j in range(1,7): d[i-1,j-1]=c[i][j]
print(d)
q=np.array([80,90,30,20,60,10])
m=d@q #计算运力,这里使用矩阵乘法
mm=m.min() #求运力的最小值
ind=np.where(m==mm)[0]+1 #python下标从0开始,np.where返回值为元组
print("运力m=",m,'\n最小运力mm=',mm,"\n选矿厂的设置位置为:",ind)
[[ 0. 20. 25. 55. 15. 30.]
[20. 0. 20. 40. 25. 40.]
[25. 20. 0. 30. 10. 25.]
[55. 40. 30. 0. 40. 55.]
[15. 25. 10. 40. 0. 15.]
[30. 40. 25. 55. 15. 0.]]
运力m= [ 4850. 4900. 5250. 11850. 4700. 8750.]
最小运力mm= 4700.0
选矿厂的设置位置为: [5]
min 1 ≤ i ≤ 6 m i = m 5 \min _{1 \leq i \leq 6} m_{i}=m_{5} min1≤i≤6mi=m5, 所以 v 5 v_{5} v5 为设置选矿厂的位置