Python、16 + 15 + 14 + 20 + 12 = 77
私は出張セールスマンタイプの問題を経験したことがありませんが、少し時間があったので、試してみようと思いました。基本的には、各ボットに特定のピクルスを割り当てて、それらに最も近いものと最も遠いものに行くための予備的な実行を行って、ピクルスを割り当てます。次に、各ボットが割り当てられたピクルスを収集する最も効率的な方法を総当たりします。
この方法がどれほど実行可能かは本当にわかりませんが、ボットが少ない大きなボードではうまく機能しないと思います(4番目のボードはすでに2分以上かかることもあります)。
コード:
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