Python,16 + 15 + 14 + 20 + 12 = 77
我真的没有任何过往推销员类型问题的经验,但是我有一点时间在手,所以我想我会试一试。它基本上是尝试通过使每个机器人在执行过程中经过一定的腌制而分配给某些机器人,在这些运行中,它们会寻找最接近它们且彼此最远离的那些。然后,它为每个机器人以最有效的方式来收集其分配的酱菜。
我真的不知道这种方法是多么可行,但是我怀疑它对于机器人更少的大型主板来说是行不通的(第四块主板有时已经超过了两分钟)。
码:
def parse_input(string):
pickles = []
size = len(string) - string.count('\n')
poses = [None] * (size - string.count('.') - string.count('P'))
for y,line in enumerate(string.strip().split('\n')):
for x,char in enumerate(line):
if char == '.':
continue
elif char == 'P':
pickles.append((x,y))
else:
poses[int(char)-1] = (x,y)
return pickles, poses
def move((px,py),(tx,ty)):
if (px,py) == (tx,ty):
return (px,py)
dx = tx-px
dy = ty-py
if abs(dx) <= abs(dy):
if dy < 0:
return (px,py-1)
else:
return (px,py+1)
else:
if dx < 0:
return (px-1,py)
else:
return (px+1,py)
def distance(pos, pickle):
return abs(pos[0]-pickle[0]) + abs(pos[1]-pickle[1])
def calc_closest(pickles,poses,index):
distances = [[distance(pos,pickle) for pickle in pickles] for pos in poses]
dist_diffs = []
for i, pickle_dists in enumerate(distances):
dist_diffs.append([])
for j, dist in enumerate(pickle_dists):
other = [d[j] for d in distances[:i]+distances[i+1:]]
dist_diffs[-1].append(min(other)-dist)
sorted = pickles[:]
sorted.sort(key = lambda ppos: -dist_diffs[index][pickles.index(ppos)])
return sorted
def find_best(items,level):
if level == 0:
best = (None, None)
for rv, rest in find_best(items[1:],level+1):
val = distance(items[0],rest[0]) + rv
if best[0] == None or val < best[0]:
best = (val, [items[0]] + rest)
return best
if len(items) == 1:
return [(0,items[:])]
size = len(items)
bests = []
for i in range(size):
best = (None, None)
for rv, rest in find_best(items[:i]+items[i+1:],level+1):
val = distance(items[i],rest[0]) + rv
if best[0] == None or val < best[0]:
best = (val, [items[i]] + rest)
if best[0] != None:
bests.append(best)
return bests
def find_best_order(pos,pickles):
if pickles == []:
return 0,[]
best = find_best([pos]+pickles,0)
return best
def walk_path(pos,path):
history = ''
while path:
npos = move(pos, path[0])
if npos == path[0]:
path.remove(path[0])
if npos[0] < pos[0]:
history += 'L'
elif npos[0] > pos[0]:
history += 'R'
elif npos[1] < pos[1]:
history += 'U'
elif npos[1] > pos[1]:
history += 'D'
pos = npos
return history
def find_paths(input_str):
pickles, poses = parse_input(input_str) ## Parse input string and stuff
orig_pickles = pickles[:]
orig_poses = poses[:]
numbots = len(poses)
to_collect = [[] for i in range(numbots)] ## Will make a list of the pickles each bot should go after
waiting = [True] * numbots
targets = [None] * numbots
while pickles:
while True in waiting: ## If any bots are waiting for a new target
index = waiting.index(True)
closest = calc_closest(pickles,poses,index) ## Prioritizes next pickle choice based upon how close they are RELATIVE to other bots
tar = closest[0]
n = 0
while tar in targets[:index]+targets[index+1:]: ## Don't target the same pickle!
other_i = (targets[:index]+targets[index+1:]).index(tar)
dist_s = distance(poses[index],tar)
dist_o = distance(poses[other_i],tar)
if dist_s < dist_o:
waiting[other_i] = True
break
n += 1
if len(closest) <= n:
waiting[index] = False
break
tar = closest[n]
targets[index] = tar
waiting[index] = False
for i in range(numbots): ## Move everything toward targets (this means that later target calculations will not be based on the original position)
npos = move(poses[i], targets[i])
if npos != poses[i]:
poses[i] = npos
if npos in pickles:
to_collect[i].append(npos)
pickles.remove(npos)
for t, target in enumerate(targets):
if target == npos:
waiting[t] = True
paths = []
sizes = []
for i,pickle_group in enumerate(to_collect): ## Lastly brute force the most efficient way for each bot to collect its allotted pickles
size,path = find_best_order(orig_poses[i],pickle_group)
sizes.append(size)
paths.append(path)
return max(sizes), [walk_path(orig_poses[i],paths[i]) for i in range(numbots)]
def collect_pickles(boards):
## Collect Pickles!
total = 0
for i,board in enumerate(boards):
result = find_paths(board)
total += result[0]
print "Board "+str(i)+": ("+ str(result[0]) +")\n"
for i,h in enumerate(result[1]):
print '\tBot'+str(i+1)+': '+h
print
print "Total Score: " + str(total)
boards = """
P.......1.
..........
P.....P...
..P.......
....P2....
...P.P....
.PP..P....
....P....P
PPPP....3.
.P..P.P..P
....P.....
P....1....
.P.....PP.
.PP....PP.
.2.P.P....
..P....P..
.P........
.....P.P..
P.....P...
.3.P.P....
..P..P..P.
..1....P.P
..........
.......2P.
...P....P3
.P...PP..P
.......P.P
..P..P..PP
..P.4P..P.
.......P..
..P...P...
.....P....
PPPP...P..
..P.......
...P......
.......P.1
.P..P....P
P2PP......
.P..P.....
..........
......PP.P
.P1..P.P..
......PP..
P..P....2.
.P.P3.....
....4..P..
.......PP.
..P5......
P.....P...
....PPP..P
""".split('\n\n')
collect_pickles(boards)
输出:
Board 0: (16)
Bot1: DLDLLLLDLLULUU
Bot2: LDLDLLDDLDRURRDR
Bot3: URDDLLLULULURU
Board 1: (15)
Bot1: ULRDRDRRDLDDLUL
Bot2: DDURURULLUUL
Bot3: ULRRDRRRURULRR
Board 2: (14)
Bot1: URRRDDDDDRLLUL
Bot2: UUURDRDDLD
Bot3: DDDLDDLUUU
Bot4: RULLLDUUUL
Board 3: (20)
Bot1: DLULUUUUULDLLLULDDD
Bot2: LURDDURRDRUUUULUULLL
Board 4: (12)
Bot1: LDDLDR
Bot2: ULUULRRR
Bot3: LUURURDR
Bot4: RRRDRDDDR
Bot5: LLDLRRRDRRRU
Total Score: 77