NP完全问题(Non-deterministic Polynomial complete problem)是没有快速算法的问题,其时间复杂度为O(n!)。通常没有完全判定问题是不是NP完全问题,但有一些经验能够帮助判断
贪婪算法是一种不追求最优解,只希望得到较为满意解的方法。贪婪法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况,所以贪婪法不要回溯。
贪婪算法是每一步都寻找最优解的做法,并非在任何情况下都可行,但易于实现且时间复杂度可以降为O(n^2)
实例:现有集合A、B、C、D、E、F,每个集合中包含一定的数字,具体内容如下表,先找出最少集合组合,能够覆盖1-10全部的数字。
根据IPO思想,实现该代码的主要分为一下三个部分
代码如下:
number = {}
number['A'] = {1, 2, 3}
number['B'] = {7, 8, 9, 10}
number['C'] = {4, 5}
number['D'] = {2, 4, 5, 7}
number['E'] = {3, 6, 8, 10}
number['F'] = {3, 6}
number_needed = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
number_covered = set()
final_set = set()
while number_needed:
best_set = None # 临时存储当前最优集合及加入最优集合后的长度
best_covered = set()
for set_name,set_number in number.items():
covered = number_covered.union(set(set_number)) # 覆盖的集合为已覆盖和临时选择的并集
if len(covered) > len(best_covered): # 当此时集合长度更大时,更换当前最优集合
best_set = set_name
best_covered = covered
# 经处理后best_set中保存这当前情况下的最优决策
# 将最优决策加入最终集合中,
number_needed = number_needed.difference(best_covered)
number_covered = best_covered
final_set.add(best_set)
print(final_set)
输出结果为:{'A', 'E', 'B', 'C'}
旅行商问题是寻找遍历所有点且路径权值和最短的路径的算法,基于传统的循环遍历查找起来其运行时间为O(n!)。使用贪心算法处理旅行商问题的原理是:
以如下例子来实现旅行商问题的贪心算法
题目:有五个城市,其距离有以下矩阵
[ [0, 14, 10, 27, 31,],
[14, 0, 11, 17, 28]
[10, 11, 0, 19, "inf"]
[27, 17, 19, 0, 7]
[31, 28, "inf", 7, 0]]
实现代码如下:
# 输入路径权值矩阵,为无向图因此对称
graphs = [[0, 14, 10, 27, 31,],
[14, 0, 11, 17, 28],
[10, 11, 0, 19, "inf"],
[27, 17, 19, 0, 7],
[31, 28, "inf", 7, 0]]
INF = float("inf")
# 遍历进行路径修改,将0和"inf"都修改为INF
for start in range(5):
for end in range(5):
if graphs[start][end] == 0 or graphs[start][end] == "inf":
graphs[start][end] = INF
path = [] # 建立存储路径的列表,当列表中存储少于4对路径时,继续执行
start = 0 # 无向图寻找最短路径为一条直线,用statr和end记录直线的两端方便后面将邻居存储为need_reserach
end = 0
need_research = graphs
path_value = 0
while len(path) < 4:
short_path_value = INF # 建立最短路径权值用来存储
short_path = []
print(need_research)
for i in range(len(need_research)):
for j in range(5):
if need_research[i][j] < short_path_value:
short_path_value = need_research[i][j]
real_line = i + start
short_path = [real_line, j]
graphs[short_path[0]][short_path[1]] = INF # 将走过的路径权值标记为无穷大
graphs[short_path[1]][short_path[0]] = INF
path.append(short_path) # 将生成的最短路径加入path中
path_value += short_path_value
print(short_path)
if len(path) == 1: # 如果时第一次生成路径则直接作为路径的起点与重点
start = short_path[0]
end = short_path[1]
else: # 否则分别检查起点或终点哪个在新生成的路径中
if start in short_path: # 如果起点在新生成的路径中,则将起点替换为其指向的邻居作为新的起点
index = short_path.index(start)
start = short_path[1-index]
else:
index = short_path.index(end)
end = short_path[1-index]
need_research = [graphs[start], graphs[end]] # 以start和end的邻居作为新的research对象
print(path)
输出结果为:[[3, 4], [3, 1], [1, 2], [2, 0]]
因此运动路径为:A -> C -> B -> D -> E