B题 企业选址问题
某企业计划在美国的50个主要城市及其周边地区销售自己生产的产品,包括某种娱乐设施和某类服装。销售在网上进行。
为了及时将网上的订货送达客户,需要在这50个城市中的一部分城市建立仓库,为此,企业调查了城市间的公路运输时间,数据在附件1中给出,其中的数字表示两个城市之间公路运输的需要天数。如从哥伦比亚到达拉斯需要3天,而到盐湖城则需要5天。企业还调查了这50个主要城市及其周边地区的人口、该种类娱乐设施和服装的目前的消费量及税率,数据见附件2,其中娱乐设施的消费税率和州的一般消费品的消费税率一致,服装的消费税率在有的州得到减免。例如,在Phoenix及其周边地区有6,828,065人,该类服装年消费7107(千美元),该类娱乐设施年消费6308(千美元),消费品税率和服装消费税率都是5.6%。
问题1:如果网上的订货需要在一天内送达,至少需要在多少个城市建仓库?在哪些城市建?
问题2:如果网上购物需要按仓库所在地缴纳消费税,企业建仓库时要考虑为消费者减少消费税以保持企业产品的竞争力。请你建模分析:如果尽可能少建仓库,订货要保证一天内送达,而且尽可能为消费者减轻消费税负担,应该在哪几个城市建立仓库?并求出各仓库的规模比和它的供应范围。
问题3:如果需要在美国建立一个娱乐设施工厂和一个服装厂为这些仓库供货,这两个厂应该分别建在哪里?
思路
总体上第一题是一个找最小支配集的问题。比较简单。这里拷贝一下他人成果
https://www.cnblogs.com/Ash-ly/p/5775934.html 感谢。侵删。
最小支配集
贪心策略:首先选择一点为树根,再按照深度优先遍历得到遍历序列,按照所得序列的反向序列的顺序进行贪心,对于一个即不属于支配集也不与支配集中的点相连的点来说,如果他的父节点不属于支配集,将其父节点加入到支配集.
伪代码:
第一步:以根节点深度优先遍历整棵树,求出每个点在深度优先遍历序列中的编号和每个点的父节点编号.
第二步:按照深度优先遍历的反向顺序检查每个点,如果当前点不属于支配集也不与支配集的点相连,且它的父节点不属于支配集,将其父节点加入到支配集,支配集中点的个数加 1, 标记当前节点, 当前节点的父节点, 当前节点的父节点的父节点,因为这些节点要么属于支配集(当前点的父节点),要么与支配集中的点相连(当前节点 和 当前节点的父节点的父节点).
这里需要根据数据的情况等,首先把代码改成python语法,并做对应修改。
具体流程
1、对excel里的数据简单的处理了一下
#-*- coding=utf-8 -*-
import xlrd
import pandas as pd
#导入xls
data=xlrd.open_workbook("C:/Users/hasee/Desktop/visualableWea.vscode/excel_out2.xls")
table = data.sheets()[0] #获得表格
#nrows = table.nrows #行数
#ncols = table.ncols #列数
#数据录入到listx,这里针对该xls文件直接指定了数值。
listx=[]
for i in range(2,52):
list1=[]
for j in range(2,53):
list1.append(table.cell(i,j).value)
listx.append(list1)
这里直接针对数据,基本没有可迁移性,仅作为记录。
2、DFS
先回忆了一下DFS.这里针对数据集做了一些小调整,考虑到以后还会用到,所以特地把参数写到外面去了。
#变量定义
pointNumSum=50
listTu=listx.copy() #拷贝用于处理
listCurDom=[] #当前支配集
#Teil1 返回DFS序列
startPoint=0 #DFS起始点
def dfsx(listT,pointNumSum,startPoint):
used=[0 for x in range(pointNumSum)] #初始化
used[startPoint]=1
ordn=[0 for x in range(pointNumSum)]
ordn[0]=startPoint
pointNum=0
def dfs(curPoint):
if listTu[curPoint][pointNumSum] >= 1: #如果还存在可以往下寻找的点
for x in range(0,pointNumSum):
if listTu[curPoint][x]==1 and used[x]==0: #找到第一个点
listTu[x][pointNumSum]=listTu[x][pointNumSum]-1
listTu[curPoint][pointNumSum]=listTu[curPoint][pointNumSum]-1
nonlocal pointNum
pointNum+=1
ordn[pointNum]=x #记录序列中第N点的编号
used[x]=1
dfs(x) #深度优先
if used[curPoint]==0:
pointNum+=1
used[curPoint]=1
ordn[pointNum]=curPoint
for y in range(0,pointNumSum): #按次序检索
dfs(y)
for x in range(0,pointNumSum):
ordn[x]+=1
return ordn
print(dfsx(listTu,pointNumSum,startPoint))
在编程中遇到了一个很经典的问题。
def fun1():
x = 5
def fun2():
x *= 2
return x
return fun2()
如上代码,调用fun1()
运行会出错:UnboundLocalError: local variable ‘x’ referenced before assignment。
def fun1():
x = 5
def fun2():
nonlocal x
x *= 2
return x
return fun2()
fun1()
Out[14]: 10
这里需要用到unlocal,来防止非全局变量被mute(?)掉。
3.MDS
Teil2 MDS
def domList(listRow):
connected=[0 for x in range(pointNumSum+1)] #connected:是否与支配点集中的点相连
answer=[]
count=49 #pointNumSum-1
for x in range(0,pointNumSum):
if (listx[listRow[0][x]-1][pointNumSum]==0):
answer.append(listRow[0][x])
connected[listRow[0][count]]=1
for x in range(0,pointNumSum):
if (connected[listRow[0][count]]==0) and listRow[0][count] not in answer:
if (listRow[1][count]!=0) and ((listRow[1][count]) not in answer): #有父节点
connected[listRow[0][count]],connected[listRow[1][count]]=1,1
if listRow[1][listRow[1][count]]!=0:
connected[listRow[1][listRow[1][count]]]=1
answer.append(listRow[1][count])
for j in range(0,pointNumSum):
if listx[listRow[1][count]][j] == 1:
connected[j]=1
count-=1
return answer
整段代码
#-*- coding=utf-8 -*-
import xlrd
import copy
import pandas as pd
#导入xls
data=xlrd.open_workbook("C:/Users/hasee/Desktop/visualableWea.vscode/excel_out2.xls")
table = data.sheets()[0] #获得表格
#nrows = table.nrows #行数
#ncols = table.ncols #列数
#数据录入到listx,这里针对该xls文件直接指定了数值。
listx=[]
for i in range(2,52):
list1=[]
for j in range(2,53):
list1.append(table.cell(i,j).value)
listx.append(list1)
#步骤如下
#1.随机指定根节点(这里是点0),并求出该节点为根节点生成的DFS树,返回的列表包含了50个点,就是深度优先遍历的顺序。
#2.反向贪心求支配集.按照深度优先遍历的反向顺序检查每个点,如果当前点不属于支配集也不与支配集的点相连,
# 且它的父节点不属于支配集,将其父节点加入到支配集,支配集中点的个数加 1, 标记当前节点,
# 当前节点的父节点, 当前节点的父节点的父节点,因为这些节点要么属于支配集(当前点的父节点),
# 要么与支配集中的点相连(当前节点 和 当前节点的父节点的父节点).
#变量定义
pointNumSum=50
listCurDom=[] #支配集
#Teil1 返回DFS序列
startPoint=0 #DFS起始点
def dfsx(listRow,pointNumSum,startPoint):
ordn,used=[-1 for x in range(pointNumSum)],[-1 for x in range(pointNumSum)]#初始化 #ordn[i]=j 编号J的城市在DFS中排第I位
par=[-1 for x in range(pointNumSum)] #记录父节点
ordn[0],used[startPoint]=startPoint,1
pointNum=0
answer=[]
def dfs(curPoint):
nonlocal pointNum
if used[curPoint]==-1:
pointNum+=1
ordn[pointNum]=curPoint
used[curPoint]=1
if listRow[curPoint][pointNumSum] >= 1: #如果还存在可以往下寻找的点
for x in range(0,pointNumSum):
if listRow[curPoint][x]==1 and used[x]==-1: #找到第一个点
listRow[x][pointNumSum]=listRow[x][pointNumSum]-1 #剩下还有x-1个点相连
listRow[curPoint][pointNumSum]=listRow[curPoint][pointNumSum]-1
pointNum+=1
ordn[pointNum]=x #记录序列中第N点的编号,1..pointNumSum
par[pointNum]=curPoint #记录序列中第N点的父节点编号
used[x]=1
dfs(x) #深度优先
for y in range(0,pointNumSum): #按次序检索
dfs(y)
for x in range(0,pointNumSum):
ordn[x]+=1
par[x]+=1
answer.append(ordn)
answer.append(par)
return answer
dfsAnswer=dfsx(copy.deepcopy(listx),pointNumSum,startPoint)
print(dfsAnswer)
#Teil2 MDS
def domList(listRow):
connected=[0 for x in range(pointNumSum+1)] #connected:是否与支配点集中的点相连
answer=[]
count=49 #pointNumSum-1
for x in range(0,pointNumSum):
if (listx[listRow[0][x]-1][pointNumSum]==0):
answer.append(listRow[0][x])
connected[listRow[0][count]]=1
for x in range(0,pointNumSum):
if (connected[listRow[0][count]]==0) and listRow[0][count] not in answer:
if (listRow[1][count]!=0) and ((listRow[1][count]) not in answer): #有父节点
connected[listRow[0][count]],connected[listRow[1][count]]=1,1
if listRow[1][listRow[1][count]]!=0:
connected[listRow[1][listRow[1][count]]]=1
answer.append(listRow[1][count])
for j in range(0,pointNumSum):
if listx[listRow[1][count]][j] == 1:
connected[j]=1
count-=1
return answer
print('')
print(domList(copy.deepcopy(dfsAnswer)))
在我码完这一切之后。我发现这个算法仅仅适用于树形。所以我还是把它保存下来了,好留着下次用。
参考文献:
https://wenku.baidu.com/view/cd4d3ef09e31433239689347.html
https://wenku.baidu.com/view/f08bbdf34693daef5ef73d24.html