【数学建模】【Python】自来水管道铺设问题(第一问)

2023-11-22 17:10

本文主要是介绍【数学建模】【Python】自来水管道铺设问题(第一问),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

代办事项:
状态:未处理
记录时间:2022/6/29/19:43
问题的发现:复习离散图论章节引发的联想和思考及反省
情况说明:在prim.py文件中的距离选取可能存在一定的问题。当下认为,该程序在每次增加“边”的时候,只是进行了已选取点所能延申的最短边,并不一定是总长的最短距离。该问题在初步处理本题目中已经注意,但后续并没有在程序中体现。应该是脱离了prim算法。
对于当前结果的态度:可以在一定程度上可以采用,但应该不是最优。
更改时间暂定为2022年7、8月。

自来水管道铺设问题

原问题

在村村通自来水工程实施过程中,从保证供水质量以及设备维护方便角度出发,某地区需要建设一个中心供水站,12个一级供水站和168个二级供水站,各级供水站的位置坐标如附件表1所示,其中类型A表示中心供水站,类型V代表一级供水站,类型P为二级供水站。附件图1是各级供水站的地理位置图。
现在要将中心供水站A处的自来水通过管道输送到一级供水站和二级供水站。按照设计要求,从中心站A铺设到一级供水站的管道为I型管道,从一级供水站出发铺设到二级供水站的管道为II型管道。
自来水管道铺设技术要求如下:

  1. 中心供水站只能和一级供水站连接(铺设I型管道),不能和二级供水站直接相连,但一级供水站之间可以连接(铺设I型管道)。
  2. 一级供水站可以与二级供水站相连(铺设II型管道),且二级供水站之间也可以连接(铺设II型管道)。
  3. 各级供水站之间的连接管道必须从上一级供水站或同一级供水站的位置坐标出发,不能从任意管道中间的一点进行连接。
  4. 相邻两个供水站之间(如果有管道相连)所需管道长度可简化为欧氏距离。
    请您结合上述管道铺设要求,建立数学模型,完成以下问题
    问题1:从中心供水站A出发,自来水管道应该如何铺设才能使管道的总里程最少?以图形给出铺设方案,并给出I型管道和II型管道总里程数。
    问题2:由于II型管道市场供应不足,急需减少从一级供水站出发铺设的II型管道总里程,初步方案是将其中两个二级供水站升级为一级供水站。问选取哪两个二级供水站,自来水管道应该如何铺设才能使铺设的II型管道总里程最少?相对问题1的方案,II型管道的总里程减少了多少公里?
    在这里插入图片描述

原始数据

# 准备原始数据
# initialData.py
coordinate_A = [26, 31]
coordinate_A_V = [[26, 31], [5, 33], [8, 9], [10, 24], [13, 34], [17, 23], [20, 10], [25, 47], [31, 18], [35, 42], [36, 25],[41, 31], [45, 38]]
coordinate_A_V_P = [[26, 31], [5, 33], [8, 9], [10, 24], [13, 34], [17, 23], [20, 10], [25, 47], [31, 18], [35, 42],[36, 25], [41, 31], [45, 38], [41, 35], [40, 34], [38, 35], [38, 37], [33, 37], [31, 36], [33, 35],[28, 32], [24, 30], [21, 31], [22, 27], [28, 29], [43, 37], [44, 39], [25, 27], [21, 29], [22, 30],[24, 32], [37, 33], [38, 33], [37, 36], [14, 13], [16, 9], [14, 7], [18, 14], [12, 6], [15, 14],[20, 13], [13, 46], [16, 39], [21, 39], [26, 44], [28, 40], [27, 42], [29, 38], [29, 44], [36, 44],[41, 40], [39, 52], [27, 49], [23, 46], [20, 46], [16, 46], [22, 44], [40, 44], [42, 40], [37, 42],[35, 49], [35, 51], [35, 52], [34, 55], [26, 53], [27, 51], [31, 51], [31, 45], [31, 41], [28, 45],[27, 35], [24, 38], [26, 39], [13, 37], [17, 36], [21, 41], [18, 41], [21, 43], [13, 39], [14, 43],[12, 43], [10, 44], [16, 44], [18, 44], [24, 44], [25, 49], [24, 49], [24, 51], [21, 48], [17, 51],[10, 34], [9, 35], [7, 37], [4, 37], [5, 42], [2, 44], [7, 32], [7, 30], [1, 24], [2, 16], [3, 18],[2, 20], [4, 24], [5, 28], [6, 24], [9, 29], [2, 33], [7, 34], [3, 30], [3, 41], [10, 36], [17, 34],[20, 22], [24, 21], [22, 17], [21, 16], [27, 19], [26, 16], [9, 16], [12, 17], [14, 15], [19, 26],[14, 28], [13, 25], [9, 19], [2, 1], [6, 6], [7, 8], [6, 14], [5, 17], [5, 16], [16, 19], [26, 13],[29, 11], [31, 14], [28, 17], [20, 19], [17, 22], [15, 23], [21, 23], [24, 23], [26, 23], [25, 25],[15, 31], [15, 29], [10, 28], [38, 26], [37, 25], [33, 21], [40, 24], [44, 44], [41, 30], [33, 24],[32, 27], [40, 14], [42, 26], [45, 33], [29, 23], [31, 30], [30, 25], [31, 23], [35, 15], [40, 16],[40, 20], [37, 20], [35, 24], [43, 23], [45, 26], [37, 28], [35, 28], [33, 29], [37, 30], [39, 30],[41, 29], [43, 31], [47, 34], [46, 43], [42, 43], [48, 45], [42, 44], [43, 50]]

问题一

从中心供水站A出发,自来水管道应该如何铺设才能使管道的总里程最少?以图形给出铺设方案,并给出I型管道和II型管道总里程数。

问题分析

依据要求,中心供水站只能和一级供水站连接(铺设I型管道),不能和二级供水站直接相连,但一级供水站之间可以连接(铺设I型管道)。故将问题1分成两部分进行研究,但两部分都遵循prim算法。第一部分,中心供水站与一级供水站做最小生成树;第二部分,由一级供水站出发,做一级供水站和二级供水站的最小生成树。

符号意义

符号意义
route_A_V中心供水站与一级供水站的连线
route_A_V_P所有供水站的连线
Already_sites已经连通的站点
distance_sites站点之间的欧式距离(作为权重)
Bool用于管理权重数据的数组(对数据进行显现和屏蔽)

代码实现

代码总共分为五个部分,全部通过python3实现。分别为pipeLaying.py文件、initialData.py文件、prim.py文件、distance.py文件、bool.py文件(在附录中都已给出)。
initialData.py文件用于准备原始数据。通过数组储存供水站的坐标。其中coordinate_A, coordinate_A_V, coordinate_A_V_P,分别用于存储中心供水站A、中心供水站A和一级供水站V、中心供水站A一级供水站V二级供水站P的坐标。
distance.py文件用于计算各个供水站之间的距离,作为后续选取路径的依据即权重。其中构造了Distance(coordinate_sites)函数,返回值为一个数组distance。
bool.py文件用于管理数据,目的在于当相关路径被选取后,将与其端点相关的不适宜的路径全部屏蔽,即对于通过Distance(coordinate_sites)函数计算得到的数据做显现或屏蔽。对于数据的正确管理,在本次代码实现中有关键性作用。
prim.py文件是prim算法的体现,问题的解决与结果的导出都依靠Prim(coordinate_sites)函数实现。在实现过程中,凭借Distance(coordinate_sites)函数提供的数据作为权重依据。同时,通过BoolSites(coordinate_sites)函数对于循环过程数据的管理避免循环的重复。
pipeLaying.py文件主要在于输出结果以及通过route_A_V,route_A_V_P,绘制管道连接图,并输出图像。

结果呈现中心供水站与一级供水站的管道图全部站点连接图,红色为上图,蓝色为二级水站

代码附录

# distance.pyimport numpy as np
import math as m# 计算站点之间距离,并返回一个数组
def Distance(coordinate_sites):number_sites = len(coordinate_sites)distance = np.zeros((number_sites,number_sites))for i in range(number_sites):for j in range(number_sites):distance_i_j = m.sqrt((coordinate_sites[i][0] - coordinate_sites[j][0])**2 + (coordinate_sites[i][1] - coordinate_sites[j][1])**2)if distance_i_j !=0:distance[i,j] = distance_i_jelse:distance_i_j = 1000     #粗略估计,算出的不同两点间的距离都小于1000(大数即可),将1000作为自身到自身的距离,return distance
#bool.pyimport numpy as npdef BoolSites(coordinate_sites):if len(coordinate_sites) == 13:bool_A_V = np.zeros((13, 13))return bool_A_Velif len(coordinate_sites) == 181:bool_A_V_P = np.zeros((181, 181))for i in range(13):for j in range(13):bool_A_V_P[i, j] = 1bool_A_V_P[0, :] = 1bool_A_V_P[:, 0] = 1return bool_A_V_P
# prim.pyimport numpy as np
from bool import BoolSites
from distance import Distance
from initialData import *def Prim(coordinate_sites):number = len(coordinate_sites)distance_sites = Distance(coordinate_sites)Bool = BoolSites(coordinate_sites)      #用于屏蔽处理if number ==13:Already_sites = [0]     #已经连上的站点,从中心供水站A开始计数0route_sites = []  # 选取的站点连接路线elif number == 181:Already_sites = Prim(coordinate_A_V)[1] #因为下面的while len(Already_sites) != number中的Already_sites是以之前的为基础route_sites = Prim(coordinate_A_V)[0]while len(Already_sites) != number:# 做屏蔽处理for i in Already_sites:for j in Already_sites:if Bool[i, j] == 0 and [i, j] not in route_sites and [j, i] not in route_sites:Bool[i, j] = 1Bool[j, i] = 1min_distance = 1000  # 用于判断选取最短距离,即局部最小权count = 0original_len = len(Already_sites)# 循环用于选择并增加新路径for i in Already_sites:# 在结束一次循环后,对于Already_sites的更改会反馈到‘for i in Already_sites'中,因为是列表。# 所以该判别语句用语循环的跳出。if original_len < len(Already_sites) and i == Already_sites[-1]:break# Bool[i,j]为0,表示可以建立新的连线;通过min_distance判断# 这里的min_distance会保留到下一个i的循环,继续对count=1时扩充的位置进行修正和确定for j in range(1, number):if min_distance >= distance_sites[i][j] and Bool[i, j] == 0:min_distance = distance_sites[i][j]count = count + 1# 相当于在route_sites和Already_sites中分别扩充一个位置if count == 1:route_sites.append([i, j])Bool[i, j] = 1Bool[j, i] = 1Already_sites.append(j)# 在本次的i下,对扩充的位置进行数据的修正和确定else:# print(count)Bool[route_sites[len(route_sites) - 1][0], route_sites[len(route_sites) - 1][1]] = 0Bool[route_sites[len(route_sites) - 1][1], route_sites[len(route_sites) - 1][0]] = 0route_sites[len(route_sites) - 1] = [i, j]Bool[route_sites[len(route_sites) - 1][0], route_sites[len(route_sites) - 1][1]] = 1Bool[route_sites[len(route_sites) - 1][1], route_sites[len(route_sites) - 1][0]] = 1Already_sites[len(Already_sites) - 1] = j# 以下两次屏蔽处理没有实际意义Bool[:, Already_sites[-1]] = 1Bool[Already_sites[-1], :] = 1return [route_sites, Already_sites]     # 导出路径结果
# pipeLaying.pyfrom distance import Distance
import numpy as np
from prim import Prim
import matplotlib.pyplot as plt
from initialData import *route_A_V = Prim(coordinate_A_V)[0]
print(route_A_V)
# 绘制AV站点之间的最优路线图
for i in route_A_V:x = [coordinate_A_V[i[0]][0], coordinate_A_V[i[1]][0]]y = [coordinate_A_V[i[0]][1], coordinate_A_V[i[1]][1]]plt.plot(x, y)
plt.show()route_A_V_P = Prim(coordinate_A_V_P)[0]
print(route_A_V_P)
# 绘制AVP站点之间的最优路线图
x = []
y = []
for i in coordinate_A_V_P:x.append(i[0])y.append(i[1])
plt.scatter(x[:13], y[:13], 15, "red")
plt.scatter(x[13:], y[13:], 10, "blue")
count = 0
sum_pipeline_A_V = 0
sum_pipeline_A_V_P = 0
for i in route_A_V_P:count += 1x = [coordinate_A_V_P[i[0]][0], coordinate_A_V_P[i[1]][0]]y = [coordinate_A_V_P[i[0]][1], coordinate_A_V_P[i[1]][1]]if count <= 12:plt.plot(x, y, color='red')sum_pipeline_A_V += Distance(coordinate_A_V_P)[i[0], i[1]]else:plt.plot(x, y, color='blue')sum_pipeline_A_V_P += Distance(coordinate_A_V_P)[i[0], i[1]]
print("sum_pipeline_A_V={}, sum_pipeline_A_V_P={}, sum_pipeline_A_V_P - sum_pipeline_A_V={}".format(sum_pipeline_A_V, sum_pipeline_A_V_P, sum_pipeline_A_V_P - sum_pipeline_A_V))
plt.show()

将所有代码分文件复制后,调试好环境是可以正常运行的。通过最后一个文件得结果,最后一个文件运行时,有时长,等待后出来第一个图,把图叉掉,输出第一部分结果,等待,出来第二个图,叉掉出结果。(具体情况,实操)
对于本文指出用了Prim算法,虽然是自己写得代码,但是和能够搜到的prim算法得代码……额,好吧。直说了,就是当时能搜到的没看懂,或者是代码本身不能用,再或者就是黎名自己不能根据代码进行套用(被恶心到了),然后自己根据算法本身大致的意思写的,比网上能看到的繁琐很多,感觉应该还算是Prim吧?!!发出来,就是分享和自我记录的。以后有机会再改改。//(数据结构算法什么的还没怎么看过,时间复杂度和空间的占用应该还有很多不足)
相对简单的应该是用Matlab处理的。可以去找找
把原始数据放上去就是为了让写作业的你们能够直接复制的,懂得都懂,拿到作业就是一个表格,用程序把数据跑进去,也OK,但这样更直接。
代码绝对是可以用PyCharm跑出来的,跑不出来就是环境没调试好。
你需要相信我。

第二题

下一篇吧,后面在放上来。
那时你应该还在。

这篇关于【数学建模】【Python】自来水管道铺设问题(第一问)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/411648

相关文章

解读为什么@Autowired在属性上被警告,在setter方法上不被警告问题

《解读为什么@Autowired在属性上被警告,在setter方法上不被警告问题》在Spring开发中,@Autowired注解常用于实现依赖注入,它可以应用于类的属性、构造器或setter方法上,然... 目录1. 为什么 @Autowired 在属性上被警告?1.1 隐式依赖注入1.2 IDE 的警告:

使用Python创建一个能够筛选文件的PDF合并工具

《使用Python创建一个能够筛选文件的PDF合并工具》这篇文章主要为大家详细介绍了如何使用Python创建一个能够筛选文件的PDF合并工具,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录背景主要功能全部代码代码解析1. 初始化 wx.Frame 窗口2. 创建工具栏3. 创建布局和界面控件4

一文详解如何在Python中使用Requests库

《一文详解如何在Python中使用Requests库》:本文主要介绍如何在Python中使用Requests库的相关资料,Requests库是Python中常用的第三方库,用于简化HTTP请求的发... 目录前言1. 安装Requests库2. 发起GET请求3. 发送带有查询参数的GET请求4. 发起PO

Python与DeepSeek的深度融合实战

《Python与DeepSeek的深度融合实战》Python作为最受欢迎的编程语言之一,以其简洁易读的语法、丰富的库和广泛的应用场景,成为了无数开发者的首选,而DeepSeek,作为人工智能领域的新星... 目录一、python与DeepSeek的结合优势二、模型训练1. 数据准备2. 模型架构与参数设置3

Python进行PDF文件拆分的示例详解

《Python进行PDF文件拆分的示例详解》在日常生活中,我们常常会遇到大型的PDF文件,难以发送,将PDF拆分成多个小文件是一个实用的解决方案,下面我们就来看看如何使用Python实现PDF文件拆分... 目录使用工具将PDF按页数拆分将PDF的每一页拆分为单独的文件将PDF按指定页数拆分根据页码范围拆分

解决java.lang.NullPointerException问题(空指针异常)

《解决java.lang.NullPointerException问题(空指针异常)》本文详细介绍了Java中的NullPointerException异常及其常见原因,包括对象引用为null、数组元... 目录Java.lang.NullPointerException(空指针异常)NullPointer

Android开发中gradle下载缓慢的问题级解决方法

《Android开发中gradle下载缓慢的问题级解决方法》本文介绍了解决Android开发中Gradle下载缓慢问题的几种方法,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、网络环境优化二、Gradle版本与配置优化三、其他优化措施针对android开发中Gradle下载缓慢的问

Python中常用的四种取整方式分享

《Python中常用的四种取整方式分享》在数据处理和数值计算中,取整操作是非常常见的需求,Python提供了多种取整方式,本文为大家整理了四种常用的方法,希望对大家有所帮助... 目录引言向零取整(Truncate)向下取整(Floor)向上取整(Ceil)四舍五入(Round)四种取整方式的对比综合示例应

python 3.8 的anaconda下载方法

《python3.8的anaconda下载方法》本文详细介绍了如何下载和安装带有Python3.8的Anaconda发行版,包括Anaconda简介、下载步骤、安装指南以及验证安装结果,此外,还介... 目录python3.8 版本的 Anaconda 下载与安装指南一、Anaconda 简介二、下载 An

Python自动化处理手机验证码

《Python自动化处理手机验证码》手机验证码是一种常见的身份验证手段,广泛应用于用户注册、登录、交易确认等场景,下面我们来看看如何使用Python自动化处理手机验证码吧... 目录一、获取手机验证码1.1 通过短信接收验证码1.2 使用第三方短信接收服务1.3 使用ADB读取手机短信1.4 通过API获取