贪心算法讲解(集合覆盖问题,旅行商问题求解)
作者:互联网
教室调度问题
假设有如下课程表,你希望将尽可能多的课程安排在某间教室上。
你没法让这些课都在这间教室上,因为有些课的上课时间有冲突。
你希望在这间教室上尽可能多的课。如何选出尽可能多且时间不冲突的课程呢?
这个问题好像很难,不是吗?实际上,算法可能简单得让你大吃-一惊。具体做法如下。
- 选出结束最早的课,它就是要在这间教室上的第一-堂课。
- 接下来,必须选择第一-堂 课结束后才开始的课。同样,你选择结束最早的课,这将是要在这间教室上的第二堂课。
- 重复这样做就能找出答案!下面来试- -试。 美术课的结束时间最早,为10:00 a.m,因此它就是第一堂课。接下来的课必须在10:00 a.m.后开始,且结束得最早。英语课不行,因为它的时间与美术课冲突,但数学课满足条件。最后,计算机课与数学课的时间是冲突的,但音乐课可以。
很多人都跟我说,这个算法太容易、太显而易见,肯定不对。但这正是贪婪算法的优点一简单易行! 贪婪算法很简单:每步都采取最优的做法。在这个示例中,你每次都选择结束最早的课。用专业术语说,就是你每步都选择局部最优解,最终得到的就是;全局最优解。信不信由你,对于这个调度问题,上述简单算法找到的就是最优解!
贪心算法可能找到的不是最优解,但接近最优解啦。
集合覆盖问题
假设你办了个广播节目,要让全美50个州的听众都收听得到。为此,你需要决定在哪些广播台播出。在每个广播台播出都需要支付费用,因此你力图在尽可能少的广播台播出。现有广播台名单如下。每个广播台都覆盖特定的区域,不同广播台的覆盖区域可能重叠。
我们用贪心算法求解
贪婪算法可化解危机!使用下面的贪婪算法可得到非常接近的解。
- 选出这样-一个广 播台,即它覆盖了最多的未覆盖州。即便这个广播台覆盖了一些已覆盖的州,也没有关系。
- 重复第-步,直到覆盖了所有的州。
代码
出于简化考虑,这里假设要覆盖的州没有那么多,广播台也没有那么多。
全部代码
语言:python
#创建一个列表,其中包含要覆盖的州
states_needed = set(["mt" ,"wa", "or", "id", "nv", "ut","ca", "az"])
#还需要有可供选择的广播台清单,我选择使用散列表来表示它
stations={}
stations['kone']=set(['id','nv','ut'])
stations['ktwo']=set(['wa','id','mt'])
stations['kthree']=set(['or','nv','ca'])
stations['kfour']=set(['nv','ut'])
stations['kfive']=set(['ca','az'])
#最后,需要使用一个集合来存储最终选择的广播台。
finnal_stations=set()
#计算答案
while len(states_needed)>0:#直到所有州都覆盖完,剩余列表的州为空
best_stations = None
state_covered = set() # states_ covered是-一个集合, 包含该广播台覆盖的所有未覆盖的州。
for station, states in stations.items():#for循环迭代每个广播台,并确定它是否是最佳的广播台。
covered=states_needed & states #剩余列表中的州 and 电视台覆盖的州 (取交集)
if len(covered)>len(state_covered): #取交集最大的电视台
best_stations=station
state_covered=covered
states_needed -=state_covered#剩余列表里州
finnal_stations.add(best_stations)
print(finnal_stations)
print('结束')
旅行商问题
旅行商问题(TravelingSalesmanProblem,TSP)一个商品推销员要去若干个城市推销商品,该推销员从一个城市出发,需要遍历所有城市一次且只能一次,回到出发地。应如何选择行进路线,以使总的行程最短。目前解决TSP问题的方法有许多种,比如:贪心算法、动态规划算法、分支限界法;也有智能算法。本文先介绍贪心算法:
数据 如下图,第一列城市名。第二列坐标x,第三列坐标y
语言:python
贪心算法思路:随便选择出发城市,然后每次选择要去的下一个城市时,都选择还没去的最近的城市。
第一步:读取数据
import pandas as pd
import numpy as np
import math
import time
dataframe = pd.read_csv("TSP.csv", sep=",", header=None)
v = dataframe.iloc[:, 1:3]#去除第一列12345678910,只保留x,y
print(v)
第二步:计算城市之间的距离
train_v= np.array(v)
train_d=train_v
#初始化距离 为10*10的全0矩阵
dist = np.zeros((train_v.shape[0],train_d.shape[0]))
#print(dist.shape)#(10,10)
#计算距离矩阵
for i in range(train_v.shape[0]):
for j in range(train_d.shape[0]):
dist[i,j] = math.sqrt(np.sum((train_v[i,:]-train_d[j,:])**2))
print(dist)
第三步:计算距离和路径
"""
s:已经遍历过的城市
dist:城市间距离矩阵
sumpath:目前的最小路径总长度
Dtemp:当前最小距离
flag:访问标记
"""
i=1
n=train_v.shape[0]#城市个数
j=0
sumpath=0#目前的最小路径总长度
s=[]#已经遍历过的城市
s.append(0)#从城市0开始
start = time.clock()
while True:
k=1#从1开始,因为人在城市0,所以我们设定先从城市1开始选择
Detemp=float('inf')#当前最小距离
while True:
flag=0#访问标记,否0
if k in s:#是否访问,如果访问过,flag设为1
flag = 1
if (flag==0) and (dist[k][s[i-1]] < Detemp):#如果未访问过,并且距离小于最小距离
j = k;
Detemp=dist[k][s[i - 1]];#当前两做城市相邻距离
k+=1#遍历下一城市
if k>=n:
break;
s.append(j)
i+=1;
sumpath+=Detemp
if i>=n:
break;
sumpath+=dist[0][j]#加上dist[0][j] 表示最后又回到起点
end = time.clock()
print("结果:")
print(sumpath)
for m in range(n):
print("%s-> "%(s[m]),end='')
print()
print("程序的运行时间是:%s"%(end-start))
该段代码借鉴 他人
代码解析:数字k表示当前我们选择前往下一个城市时,我们需要计算所有未访问过的城市和当前城市距离。
数字i 用于控制访问过的城市,我们需要到达每一个城市。
代码中有两个while
里面那个while表示选择下一城市时,需要遍历所有未访问过的城市,然后选择距离当前城市最近的城市,赋值给j
外面while,表示我们的每一步,我们需要去每个城市。
作者:电气-余登武
标签:广播台,stations,城市,算法,train,讲解,print,贪心 来源: https://blog.csdn.net/kobeyu652453/article/details/112390590