Pratiquez l'utilisation d'une structure en bois.
#!/bin/env python
# coding:utf-8
import csv
import sys
"""
La recherche est également effectuée lors de la création récursive d'une structure arborescente à partir du nœud racine avec la priorité donnée à la profondeur.
L'agrégation des coûts est également effectuée à mi-chemin et lorsque le coût minimum est dépassé, la recherche ultérieure des nœuds descendants est arrêtée.
Je ne suis pas habitué à écrire des programmes structurés en arborescence, alors je les ai codés simplement.
"""
class Accumulator(object):
def __init__(self, sum=sys.maxsize, route=[]):
self.sum = sum
self.route = route
class Node(object):
def __init__(self, id, parent=None, cost_from_root=0, children=[]):
self.id = id
self.parent = parent
self.cost_from_root = cost_from_root
self.children = children
def __repr__(self):
return "%i, cost: %i -> %s\n" % (self.id, self.cost_from_root, repr(self.children))
class DeliveryCostCalculator(object):
def __init__(self, filename):
self.filename = filename
self.cost_table = self.get_table()
self.acc = Accumulator(sys.maxsize, [])
def get_table(self):
cost_table = []
with open(self.filename, 'r') as f:
reader = csv.reader(f)
for row in reader:
cost_table.append([int(col) for col in row])
return cost_table
def calc_total_cost(self, current):
#S'il n'y en a plus, coût total
tmp = Node(0, current, current.cost_from_root + self.cost_table[current.id][0], None)
current.children.append(tmp)
if tmp.cost_from_root < self.acc.sum:
#Si le coût est le plus bas, agréger également la liste des itinéraires et la transmettre à l'accumulateur
self.acc.sum = tmp.cost_from_root
def _min_r(n, acc):
if n.parent is None:
acc.append(n)
return acc
acc.append(n)
return _min_r(n.parent, acc)
self.acc.route = _min_r(tmp, [])
self.acc.route.reverse()
def main(self):
def _f(slot, current):
if len(slot) <= 0:
self.calc_total_cost(current)
return
for i in slot:
#Enregistrer le nœud suivant dans l'enfant
tmp = Node(i, current, current.cost_from_root + self.cost_table[current.id][i])
if self.acc.sum < tmp.cost_from_root:
#Si le coût à ce stade dépasse le coût minimum, arrêtez toute exploration supplémentaire
return
current.children.append(tmp)
#Supprimer le numéro ajouté de la liste et se répéter
a = list(slot)
a.remove(i)
_f(a, tmp)
_f(range(1, len(self.cost_table)), Node(0))
return self.acc.sum, self.acc.route
if __name__ == "__main__":
c = DeliveryCostCalculator(sys.argv[1])
(sum, route) = c.main()
print(sum)
print(" -> ".join([str(n.id + 1) for n in route]))
# print([(n.id + 1, n.cost_from_root) for n in route])
Créez une séquence qui n'autorise pas la répétition avec des «permutations», puis utilisez «pour» pour regrouper les coûts.
Je voulais aussi faire quelque chose de cool avec functools.reduce
, mais je ne pouvais pas bien le faire.
#!/bin/env python
# coding:utf-8
import csv
import sys
from itertools import permutations
def get_table(filename):
cost_table = []
with open(filename, 'r') as f:
reader = csv.reader(f)
for row in reader:
cost_table.append([int(col) for col in row])
return cost_table
def main(filename):
cost_table = get_table(filename)
min_cost = sys.maxsize
min_route = ()
for p in permutations(range(1, len(cost_table))):
# add an initial and a last node
p = (0,) + p + (0,)
total_cost = 0
for i in range(len(p)):
if i == len(p) - 1:
continue
# get a cost between a current and next
total_cost += cost_table[p[i]][p[i + 1]]
if min_cost < total_cost:
break
# print(total_cost, p)
if total_cost < min_cost:
min_cost = total_cost
min_route = p
return min_cost, min_route
if __name__ == "__main__":
c, r = main(sys.argv[1])
print(c)
print(" -> ".join([str(n + 1) for n in r]))